From 916bfd88d30bf36b0526b0bcf1febfa4fddc211a Mon Sep 17 00:00:00 2001 From: John Goerzen Date: Wed, 16 Jul 2008 13:03:39 -0500 Subject: [PATCH] Imported Upstream version 1.3.5 --- .cvsignore | 1 + .hgignore | 6 - .hgtags | 6 - AUTHORS | 6 + Makefile.in | 65 +- an1.c | 140 +- avltree.c | 723 ++ avltree.h | 94 + axim_gpb.c | 4 +- bcr.c | 7 +- cet_util.c | 20 +- cetus.c | 58 +- chkdoc | 2 +- config.h.in | 12 + configure | 322 +- configure.in | 119 +- csv_util.c | 873 +- csv_util.h | 1 + defs.h | 43 +- delgpl.c | 16 +- destinator.c | 588 ++ dg-100.c | 689 ++ discard.c | 14 + dmtlog.c | 133 +- exif.c | 490 ++ filter_vecs.c | 28 +- garmin.c | 103 +- garmin_fs.c | 45 +- garmin_gpi.c | 197 +- garmin_tables.c | 3 +- garmin_txt.c | 255 +- gbfile.c | 79 +- gbfile.h | 1 + gbser_posix.c | 11 +- gbversion.h | 4 +- gbversion.h.in | 2 +- gdb.c | 48 +- google.c | 14 +- gpsbabel.html | 1249 ++- gpssim.c | 16 +- gpx.c | 79 +- gtrnctr.c | 44 +- holux.c | 20 +- ik3d.c | 196 + internal_styles.c | 76 +- jeeps/gpsapp.c | 8 +- jeeps/gpsdatum.h | 42 +- jeeps/gpsinput.c | 2 +- jeeps/gpsmath.c | 388 +- jeeps/gpsmath.h | 14 + kml.c | 490 +- lmx.c | 246 + lowranceusr.c | 565 +- mac/dmg-contents/COPYING | 339 + mac/dmg-contents/Credits.rtf | 53 + mac/dmg-contents/GPSBabel+.app | Bin 0 -> 2342908 bytes mac/dmg-contents/README.rtf | 15 + mac/include/expat.h | 927 +++ mac/lib/libexpat.a | Bin 0 -> 538508 bytes .../MacGPSBabel.xcodeproj/project.pbxproj | 50 +- maggeo.c | 14 +- magproto.c | 41 +- main.c | 7 +- mapsend.c | 2 +- mapsource.c | 758 +- mingw/includew/expat.h | 1013 +++ mingw/includew/expat_external.h | 115 + msroute.c | 73 +- msvc/Expat/expat.h | 2002 ++--- msvc/GPSBabel-msvc7.vcproj | 117 +- msvc/GPSBabel.vcproj | 6603 +++++++-------- msvc/config.h | 6 +- mtk_logger.c | 1149 +++ navilink.c | 970 +++ nmea.c | 83 +- osm.c | 926 +++ overlay.c | 121 +- ozi.c | 118 +- parse.c | 237 + pcx.c | 6 +- pdbfile.c | 8 +- pdbfile.h | 8 +- psp.c | 212 +- random.c | 208 + reference/IMG_2065.JPG | Bin 0 -> 18399 bytes reference/destinator_poi.dat | Bin 0 -> 10492 bytes reference/destinator_poi.txt | 87 + reference/earth-expertgps.kml | 139 +- reference/earth-gc.kml | 173 +- reference/exif-dat.csv | 2 + reference/expertgps-g7t.txt | 130 +- reference/garmin_txt.txt | 84 +- reference/geocaching.gpx | 73 + reference/ik3d-sample.gpx | 139 + reference/ik3d-sample.ikt | 433 + reference/lowrance.usr | Bin 353 -> 622 bytes reference/navilink_tracks.gpx | 2084 +++++ reference/navilink_tracks.trk | Bin 0 -> 11040 bytes reference/navilink_tracks_gpx.trk | Bin 0 -> 11040 bytes reference/navilink_waypoints.gpx | 74 + reference/navilink_waypoints.wpt | Bin 0 -> 256 bytes reference/navilink_waypoints_gpx.wpt | Bin 0 -> 256 bytes reference/nokia.lmx | 112 + reference/osm-data.gpx | 400 + reference/osm-data.xml | 139 + reference/ozi.wpt | 18 +- reference/route/destinator_itn.dat | Bin 0 -> 5752 bytes reference/route/destinator_itn.txt | 47 + reference/stmsdf.txt | 86 +- reference/track/destinator_trl.dat | Bin 0 -> 3952 bytes reference/track/destinator_trl.txt | 27 + reference/track/mtk_logger.bin | Bin 0 -> 65536 bytes reference/track/mtk_logger.csv | 818 ++ reference/track/mtk_logger.gpx | 7391 +++++++++++++++++ reference/track/nmea+ms.gpx | 290 + reference/track/nmea+ms.txt | 125 + reference/track/nmea.gpx | 308 +- reference/track/stmsdf-track.sdf | 70 +- reference/track/vidaone.csv | 65 + reference/track/vidaone.gpb | Bin 0 -> 1280 bytes reference/xol-sample-gpx.xol | 182 + reference/xol-sample.gpx | 167 + reference/xol-sample.xol | 182 + saroute.c | 98 +- stmsdf.c | 2 +- style/ktf2.style | 1 + style/s_and_t.style | 2 +- style/sportsim.style | 1 + style/tomtom_itn.style | 2 +- test-all | 7 +- testo | 84 +- tomtom.c | 77 +- tools/mac-config | 12 + tools/mkcapabilities.in | 2 +- tools/mkdmg | 40 + tpg.c | 118 +- tpo.c | 271 +- unicsv.c | 358 +- util.c | 176 +- vcf.c | 8 +- vecs.c | 196 +- vidaone.c | 134 + vitosmt.c | 95 +- waypt.c | 104 +- win32/GPSBabelGUI.exe | Bin 1038088 -> 1057288 bytes win32/gpsbabel.rc.in | 6 +- win32/gui-2/GPSBabelGUI.cfg | 2 +- win32/gui-2/GPSBabelGUI.dof | 8 +- win32/gui-2/GPSBabelGUI.dpr | 5 +- win32/gui-2/GPSBabelGUI.res | Bin 1748 -> 1752 bytes win32/gui-2/Makefile | 6 +- win32/gui-2/about.dfm | Bin 3505 -> 3505 bytes win32/gui-2/about.pas | 2 +- win32/gui-2/common.pas | 8 +- win32/gui-2/filter.dfm | Bin 8943 -> 8971 bytes win32/gui-2/filter.pas | 18 +- win32/gui-2/gpsbabel.iss | 10 +- win32/gui-2/gpsbabel.po | 89 +- win32/gui-2/locale/de/LC_MESSAGES/gpsbabel.po | 908 +- win32/gui-2/locale/es/LC_MESSAGES/gpsbabel.po | 903 +- win32/gui-2/locale/fr/LC_MESSAGES/gpsbabel.po | 906 +- win32/gui-2/locale/hu/LC_MESSAGES/gpsbabel.po | 99 +- win32/gui-2/main.dfm | Bin 37208 -> 38547 bytes win32/gui-2/main.pas | 253 +- win32/gui-2/options.dfm | Bin 1313 -> 1332 bytes win32/gui-2/options.pas | 30 +- win32/gui-2/readme.pas | 2 +- win32/gui-2/select.pas | 18 + win32/gui-2/utils.pas | 95 +- xcsv.c | 2 +- xcsv_tokens.gperf | 289 + xcsv_tokens.in | 71 + xmldoc/chapters/build.xml | 8 +- xmldoc/chapters/preface.xml | 12 +- xmldoc/chapters/styles.xml | 62 + xmldoc/chapters/use.xml | 59 +- xmldoc/filters/discard.xml | 24 +- xmldoc/filters/options/discard-sat.xml | 4 + xmldoc/formats/csv.xml | 11 +- xmldoc/formats/destinator_itn.xml | 18 + xmldoc/formats/destinator_poi.xml | 19 + xmldoc/formats/destinator_trl.xml | 18 + xmldoc/formats/dg-100.xml | 19 + xmldoc/formats/exif.xml | 12 + xmldoc/formats/g7towin.xml | 2 +- xmldoc/formats/garmin.xml | 49 + xmldoc/formats/garmin_gpi.xml | 15 +- xmldoc/formats/ggv_log.xml | 2 +- xmldoc/formats/google.xml | 2 +- xmldoc/formats/gpsdrive.xml | 2 +- xmldoc/formats/gpx.xml | 2 +- xmldoc/formats/ik3d.xml | 11 + xmldoc/formats/kml.xml | 29 +- xmldoc/formats/ktf2.xml | 4 +- xmldoc/formats/lmx.xml | 6 + xmldoc/formats/magellan1.xml | 50 + xmldoc/formats/msroute.xml | 4 +- xmldoc/formats/msroute1.xml | 4 +- xmldoc/formats/mtk-bin.xml | 26 + xmldoc/formats/mtk.xml | 21 + xmldoc/formats/navilink.xml | 32 + xmldoc/formats/options/dg-100-erase.xml | 1 + xmldoc/formats/options/exif-filename.xml | 10 + .../formats/options/garmin-bitscategory.xml | 19 + xmldoc/formats/options/garmin-resettime.xml | 10 + xmldoc/formats/options/garmin_gpi-alerts.xml | 15 + .../formats/options/garmin_gpi-proximity.xml | 64 + xmldoc/formats/options/garmin_gpi-sleep.xml | 16 + xmldoc/formats/options/garmin_gpi-speed.xml | 66 + xmldoc/formats/options/garmin_gpi-unique.xml | 9 + xmldoc/formats/options/garmin_gpi-units.xml | 7 + xmldoc/formats/options/garmin_txt-grid.xml | 6 + xmldoc/formats/options/gdb-bitscategory.xml | 19 + xmldoc/formats/options/gdb-roadbook.xml | 6 +- xmldoc/formats/options/gpx-logpoint.xml | 7 +- xmldoc/formats/options/gpx-snlen.xml | 4 +- xmldoc/formats/options/gpx-suppresswhite.xml | 4 +- xmldoc/formats/options/gpx-urlbase.xml | 3 + xmldoc/formats/options/kml-trackdirection.xml | 4 + xmldoc/formats/options/magellan-deficon.xml | 4 +- xmldoc/formats/options/magellanx-deficon.xml | 4 +- xmldoc/formats/options/mtk-bin-csv.xml | 8 + xmldoc/formats/options/mtk-csv.xml | 2 + xmldoc/formats/options/mtk-erase.xml | 1 + .../formats/options/navicache-noretired.xml | 4 +- xmldoc/formats/options/navilink-nukerte.xml | 10 + xmldoc/formats/options/navilink-nuketrk.xml | 10 + xmldoc/formats/options/navilink-nukewpt.xml | 10 + xmldoc/formats/options/navilink-power_off.xml | 4 + xmldoc/formats/options/nmea-gisteq.xml | 17 + xmldoc/formats/options/osm-tag.xml | 6 + xmldoc/formats/options/osm-tagnd.xml | 6 + xmldoc/formats/options/ozi-proximity.xml | 4 + xmldoc/formats/options/ozi-snlen.xml | 4 +- xmldoc/formats/options/ozi-snunique.xml | 4 +- xmldoc/formats/options/ozi-snupper.xml | 4 +- xmldoc/formats/options/ozi-snwhite.xml | 4 +- xmldoc/formats/options/ozi-wptbgcolor.xml | 4 +- xmldoc/formats/options/ozi-wptfgcolor.xml | 4 +- xmldoc/formats/options/pathaway-deficon.xml | 4 +- xmldoc/formats/options/pathaway-snlen.xml | 4 +- xmldoc/formats/options/pcx-cartoexploreur.xml | 5 +- xmldoc/formats/options/pcx-deficon.xml | 4 +- xmldoc/formats/options/unicsv-utc.xml | 5 + xmldoc/formats/options/wfff-ahcicon.xml | 4 +- xmldoc/formats/options/wfff-ahoicon.xml | 3 + xmldoc/formats/options/wfff-aicicon.xml | 4 +- xmldoc/formats/options/wfff-aioicon.xml | 3 + xmldoc/formats/options/wfff-snmac.xml | 4 +- xmldoc/formats/osm.xml | 13 + xmldoc/formats/s_and_t.xml | 7 +- xmldoc/formats/unicsv.xml | 16 +- xmldoc/formats/vidaone.xml | 7 + xmldoc/formats/wbt-bin.xml | 4 +- xmldoc/formats/wbt.xml | 23 +- xmldoc/formats/wfff.xml | 2 +- xmldoc/formats/xol.xml | 7 + xol.c | 354 + 258 files changed, 36245 insertions(+), 9340 deletions(-) delete mode 100644 .hgignore delete mode 100644 .hgtags create mode 100644 avltree.c create mode 100644 avltree.h create mode 100644 destinator.c create mode 100644 dg-100.c create mode 100644 exif.c create mode 100644 ik3d.c create mode 100644 lmx.c create mode 100644 mac/dmg-contents/COPYING create mode 100644 mac/dmg-contents/Credits.rtf create mode 100755 mac/dmg-contents/GPSBabel+.app create mode 100644 mac/dmg-contents/README.rtf create mode 100644 mac/include/expat.h create mode 100644 mac/lib/libexpat.a create mode 100644 mingw/includew/expat.h create mode 100644 mingw/includew/expat_external.h create mode 100644 mtk_logger.c create mode 100644 navilink.c create mode 100644 osm.c create mode 100644 parse.c create mode 100644 random.c create mode 100644 reference/IMG_2065.JPG create mode 100644 reference/destinator_poi.dat create mode 100644 reference/destinator_poi.txt create mode 100644 reference/exif-dat.csv create mode 100644 reference/geocaching.gpx create mode 100644 reference/ik3d-sample.gpx create mode 100644 reference/ik3d-sample.ikt create mode 100644 reference/navilink_tracks.gpx create mode 100755 reference/navilink_tracks.trk create mode 100755 reference/navilink_tracks_gpx.trk create mode 100644 reference/navilink_waypoints.gpx create mode 100755 reference/navilink_waypoints.wpt create mode 100644 reference/navilink_waypoints_gpx.wpt create mode 100644 reference/nokia.lmx create mode 100644 reference/osm-data.gpx create mode 100644 reference/osm-data.xml create mode 100644 reference/route/destinator_itn.dat create mode 100644 reference/route/destinator_itn.txt create mode 100644 reference/track/destinator_trl.dat create mode 100644 reference/track/destinator_trl.txt create mode 100644 reference/track/mtk_logger.bin create mode 100644 reference/track/mtk_logger.csv create mode 100644 reference/track/mtk_logger.gpx create mode 100644 reference/track/nmea+ms.gpx create mode 100644 reference/track/nmea+ms.txt create mode 100644 reference/track/vidaone.csv create mode 100644 reference/track/vidaone.gpb create mode 100644 reference/xol-sample-gpx.xol create mode 100644 reference/xol-sample.gpx create mode 100644 reference/xol-sample.xol create mode 100755 tools/mac-config create mode 100755 tools/mkdmg create mode 100644 vidaone.c create mode 100644 xcsv_tokens.gperf create mode 100644 xcsv_tokens.in create mode 100644 xmldoc/filters/options/discard-sat.xml create mode 100644 xmldoc/formats/destinator_itn.xml create mode 100644 xmldoc/formats/destinator_poi.xml create mode 100644 xmldoc/formats/destinator_trl.xml create mode 100644 xmldoc/formats/dg-100.xml create mode 100644 xmldoc/formats/exif.xml create mode 100644 xmldoc/formats/ik3d.xml create mode 100644 xmldoc/formats/lmx.xml create mode 100644 xmldoc/formats/mtk-bin.xml create mode 100644 xmldoc/formats/mtk.xml create mode 100644 xmldoc/formats/navilink.xml create mode 100644 xmldoc/formats/options/dg-100-erase.xml create mode 100644 xmldoc/formats/options/exif-filename.xml create mode 100644 xmldoc/formats/options/garmin-bitscategory.xml create mode 100644 xmldoc/formats/options/garmin-resettime.xml create mode 100644 xmldoc/formats/options/garmin_gpi-alerts.xml create mode 100644 xmldoc/formats/options/garmin_gpi-proximity.xml create mode 100644 xmldoc/formats/options/garmin_gpi-sleep.xml create mode 100644 xmldoc/formats/options/garmin_gpi-speed.xml create mode 100644 xmldoc/formats/options/garmin_gpi-unique.xml create mode 100644 xmldoc/formats/options/garmin_gpi-units.xml create mode 100644 xmldoc/formats/options/gdb-bitscategory.xml create mode 100644 xmldoc/formats/options/kml-trackdirection.xml create mode 100644 xmldoc/formats/options/mtk-bin-csv.xml create mode 100644 xmldoc/formats/options/mtk-csv.xml create mode 100644 xmldoc/formats/options/mtk-erase.xml create mode 100644 xmldoc/formats/options/navilink-nukerte.xml create mode 100644 xmldoc/formats/options/navilink-nuketrk.xml create mode 100644 xmldoc/formats/options/navilink-nukewpt.xml create mode 100644 xmldoc/formats/options/navilink-power_off.xml create mode 100644 xmldoc/formats/options/nmea-gisteq.xml create mode 100644 xmldoc/formats/options/osm-tag.xml create mode 100644 xmldoc/formats/options/osm-tagnd.xml create mode 100644 xmldoc/formats/options/ozi-proximity.xml create mode 100644 xmldoc/formats/options/unicsv-utc.xml create mode 100644 xmldoc/formats/osm.xml create mode 100644 xmldoc/formats/vidaone.xml create mode 100644 xmldoc/formats/xol.xml create mode 100644 xol.c diff --git a/.cvsignore b/.cvsignore index 45d939897..1ead503aa 100644 --- a/.cvsignore +++ b/.cvsignore @@ -18,5 +18,6 @@ config.status CHANGELOG +autom4te.cache coldsync pilot-link diff --git a/.hgignore b/.hgignore deleted file mode 100644 index ca0a92794..000000000 --- a/.hgignore +++ /dev/null @@ -1,6 +0,0 @@ -(^|/)\_darcs($|/) -(^|/)\.hg($|/) -(^|/)\.hgtags($|/) -^state$ -^state.old$ -^state.journal$ diff --git a/.hgtags b/.hgtags deleted file mode 100644 index c94b23edc..000000000 --- a/.hgtags +++ /dev/null @@ -1,6 +0,0 @@ -10ec18aa4b5b46d86a25c7f0090269d855ad30ee UPSTREAM_gpsbabel_1.2.4 -2c162c23811cef770de7137b8c7df6466f18c95f UPSTREAM_gpsbabel_1.3.2 -1f8aaa3ac6d400efcf6c570f63fa2f09e048d478 UPSTREAM_gpsbabel_1.3.3 -7fff9b65563522c02364ba8d246477a466818c9a UPSTREAM_gpsbabel_1.3.3_TAG -cd74b2ab291a6fa2abea2d9c2bad735a728c5325 UPSTREAM_gpsbabel_1.3.4 -0ee1b52bc35ec5674d7b9910a755a79323f72f54 UPSTREAM_gpsbabel_1.3.4_TAG diff --git a/AUTHORS b/AUTHORS index 3e09d772a..be7d14f4c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -13,6 +13,7 @@ Major contributors: Other contributors and helpers: * Alan Bleasby +* Alan Porter * Andrew Arensburger * Andrew Kirmse * Andy Armstrong @@ -28,6 +29,7 @@ Other contributors and helpers: * Frank Warmerdam * Fredie Kern * Gary Paulson +* Gerhard Olsson * Gunar Megger * Gustavo Niemeyer * Harald Nordius @@ -44,7 +46,9 @@ Other contributors and helpers: * Justin Broughton * Kjeld Jensen * Lilian Morinon +* Ling Nero * Mark Bradley +* Mirko Parthey * Oyvind Kaurstad * P. Rosen * Pasha Phares @@ -52,6 +56,7 @@ Other contributors and helpers: * Paul Fox * Paul Merchant * Paul Tomblin +* Per Borgentun * Richard Messeder * Rick Richardson * Robert Shaw @@ -61,4 +66,5 @@ Other contributors and helpers: * Sven Dovideit * Tim Zickus * Tobias Minich +* Tom Hughes * Vladimir Nadvornik diff --git a/Makefile.in b/Makefile.in index 4366b462e..7da093f41 100644 --- a/Makefile.in +++ b/Makefile.in @@ -9,7 +9,7 @@ RELEASE=@PACKAGE_RELEASE@ VERSIOND=$(VERSD)$(RELEASE) VERSIONU=$(VERSU)$(RELEASE) -DOCVERSION=@PACKAGE_VERSION@ +DOCVERSION=@DOCVERSION@ # DOCVERSION=development CC=@CC@ @@ -42,20 +42,25 @@ INSTALL_DIR=$(DESTDIR)/$(PREFIX) # OTHER_ROOT=/opt/local # For DarwinPorts on OSX # OTHER_ROOT=/sw # Uncomment For Fink on OS X. -FMTS=magproto.o gpx.o geo.o mapsend.o mapsource.o garmin_tables.o \ - gtm.o \ - gpsutil.o pcx.o cetus.o copilot.o gpspilot.o magnav.o \ - psp.o holux.o garmin.o tmpro.o tpg.o tpo.o \ - xcsv.o gcdb.o tiger.o internal_styles.o easygps.o quovadis.o \ +MINIMAL_FMTS=magproto.o gpx.o geo.o mapsend.o mapsource.o garmin.o \ + garmin_tables.o internal_styles.o nmea.o kml.o + +ALL_FMTS=$(MINIMAL_FMTS) gtm.o gpsutil.o pcx.o cetus.o copilot.o \ + gpspilot.o magnav.o \ + psp.o holux.o tmpro.o tpg.o tpo.o \ + xcsv.o gcdb.o tiger.o easygps.o quovadis.o \ gpilots.o saroute.o navicache.o psitrex.o geoniche.o delgpl.o \ - ozi.o nmea.o text.o html.o palmdoc.o netstumbler.o hsa_ndv.o \ + ozi.o text.o html.o palmdoc.o netstumbler.o hsa_ndv.o \ igc.o brauniger_iq.o shape.o hiketech.o glogbook.o coastexp.o \ - vcf.o overlay.o kml.o google.o lowranceusr.o an1.o tomtom.o \ + vcf.o overlay.o google.o xhtmlent.o lowranceusr.o an1.o tomtom.o \ tef_xml.o maggeo.o pathaway.o vitosmt.o gdb.o bcr.o coto.o \ ignrando.o stmwpp.o msroute.o cst.o nmn4.o mag_pdb.o compegps.o \ yahoo.o unicsv.o wfff_xml.o garmin_txt.o axim_gpb.o gpssim.o \ wbt-200.o stmsdf.o gtrnctr.o dmtlog.o raymarine.o alan.o vitovtt.o \ - ggv_log.o g7towin.o garmin_gpi.o + ggv_log.o g7towin.o garmin_gpi.o lmx.o random.o xol.o dg-100.o \ + navilink.o mtk_logger.o ik3d.o osm.o destinator.o exif.o vidaone.o + +FMTS=@FMTS@ FILTERS=position.o radius.o duplicate.o arcdist.o polygon.o smplrout.o \ reverse_route.o sort.o stackfilter.o trackfilter.o discard.o \ @@ -84,8 +89,8 @@ ZLIB=zlib/adler32.o zlib/compress.o zlib/crc32.o zlib/deflate.o zlib/inffast.o \ LIBOBJS = queue.o route.o waypt.o filter_vecs.o util.o vecs.o mkshort.o \ csv_util.o strptime.o grtcirc.o vmem.o util_crc.o xmlgeneric.o \ uuid.o formspec.o xmltag.o cet.o cet_util.o fatal.o rgbcolors.o \ - xhtmlent.o inifile.o garmin_fs.o gbsleep.o units.o @GBSER@ gbser.o \ - gbfile.o \ + inifile.o garmin_fs.o gbsleep.o units.o @GBSER@ gbser.o \ + gbfile.o parse.o avltree.o \ $(PALM_DB) $(GARMIN) $(JEEPS) $(SHAPE) @ZLIB@ $(FMTS) $(FILTERS) OBJS = main.o globals.o $(LIBOBJS) @FILEINFO@ @@ -109,6 +114,9 @@ gpsbabel-debug: $(OBJS) Makefile gbversion.h: Makefile.in config.status xmldoc/makedoc.in gbversion.h.in CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status +xcsv_tokens.gperf: xcsv_tokens.in + gperf -L ANSI-C -D -t $? > $@ + config.status: configure $(SHELL) config.status --recheck @@ -301,8 +309,11 @@ release-upload: /tmp/gpsbabel-$(VERSIOND).tar.gz /tmp/gpsbabel-$(VERSIOND).zip @(. tools/functions && ask "Type 'yes' if you want to do the upload now" "yes" ) curl -u anonymous:anonymous --upload-file /tmp/gpsbabel-$(VERSIOND).tar.gz ftp://upload.sf.net/incoming/ curl -u anonymous:anonymous --upload-file /tmp/gpsbabel-$(VERSIOND).zip ftp://upload.sf.net/incoming/ - curl -u anonymous:anonymous --upload-file /tmp/dist/SRPMS/gpsbabel-$(VERSIOND)-0.src.rpm ftp://upload.sf.net/incoming/ - curl -u anonymous:anonymous --upload-file /tmp/dist/RPMS/i386/gpsbabel-$(VERSIOND)-0.i386.rpm ftp://upload.sf.net/incoming/ + curl -u anonymous:anonymous --upload-file /tmp/dist/SRPMS/gpsbabel-$(VERSIOND).src.rpm ftp://upload.sf.net/incoming/ + curl -u anonymous:anonymous --upload-file /tmp/dist/RPMS/i386/gpsbabel-$(VERSIOND).i386.rpm ftp://upload.sf.net/incoming/ + +mac-upload: + curl -u anonymous:anonymous --upload-file GPSBabel+-$(VERSIOND).dmg ftp://upload.sf.net/incoming/ release: release-sourcecheck release-tarball release-winbuild release-rpm release-upload @@ -321,6 +332,12 @@ msvc-build: echo $(OBJS) > objs.lst LINK.EXE /NOLOGO @objs.lst ./msvc/expat/libexpat.lib /out:gpsbabel.exe +# release check using CVS tree +test-release: doc gpsbabel.html + cvs export -r HEAD -d gpsbabel-$(VERSIOND) gpsbabel + rm -f gpsbabel-$(VERSIOND)/internal_styles.c + make release-tarball release-winbuild release-rpm + # Machine generated from here down. alan.o: alan.c defs.h config.h queue.h gbtypes.h zlib/zlib.h zlib/zconf.h \ gbfile.h cet.h cet_util.h inifile.h @@ -328,6 +345,7 @@ an1.o: an1.c defs.h config.h queue.h gbtypes.h zlib/zlib.h zlib/zconf.h \ gbfile.h cet.h cet_util.h inifile.h an1sym.h arcdist.o: arcdist.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h filterdefs.h grtcirc.h +avltree.o: avltree.h avltree.c defs.h gbtypes.h config.h axim_gpb.o: axim_gpb.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h bcr.o: bcr.c defs.h config.h queue.h gbtypes.h zlib/zlib.h zlib/zconf.h \ @@ -370,7 +388,7 @@ csv_util.o: csv_util.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ jeeps/gpsdevice.h jeeps/gpssend.h jeeps/gpsread.h jeeps/gpsutil.h \ jeeps/gpsapp.h jeeps/gpsprot.h jeeps/gpscom.h jeeps/gpsfmt.h \ jeeps/gpsmath.h jeeps/gpsmem.h jeeps/gpsrqst.h jeeps/gpsinput.h \ - jeeps/gpsproj.h xmlgeneric.h + jeeps/gpsproj.h xmlgeneric.h xcsv_tokens.gperf garmin_fs.h delgpl.o: delgpl.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h discard.o: discard.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ @@ -386,6 +404,9 @@ duplicate.o: duplicate.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h filterdefs.h easygps.o: easygps.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h +exif.o: exif.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ + zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h garmin_tables.h \ + strptime.h fatal.o: fatal.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h filter_vecs.o: filter_vecs.c defs.h config.h queue.h gbtypes.h \ @@ -517,6 +538,8 @@ igc.o: igc.c defs.h config.h queue.h gbtypes.h zlib/zlib.h zlib/zconf.h \ gbfile.h cet.h cet_util.h inifile.h ignrando.o: ignrando.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h xmlgeneric.h +ik3d.o: ik3d.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ + zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h xmlgeneric.h inifile.o: inifile.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h internal_styles.o: internal_styles.c defs.h config.h queue.h gbtypes.h \ @@ -561,6 +584,8 @@ msroute.o: msroute.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ jeeps/gpssend.h jeeps/gpsread.h jeeps/gpsutil.h jeeps/gpsapp.h \ jeeps/gpsprot.h jeeps/gpscom.h jeeps/gpsfmt.h jeeps/gpsmath.h \ jeeps/gpsmem.h jeeps/gpsrqst.h jeeps/gpsinput.h jeeps/gpsproj.h +mtk_logger.o: mtk_logger.c defs.h config.h queue.h gbtypes.h \ + gbfile.h cet.h cet_util.h inifile.h gbser.h navicache.o: navicache.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h netstumbler.o: netstumbler.c defs.h config.h queue.h gbtypes.h \ @@ -575,6 +600,9 @@ nmn4.o: nmn4.c defs.h config.h queue.h gbtypes.h zlib/zlib.h zlib/zconf.h \ gbfile.h cet.h cet_util.h inifile.h csv_util.h nukedata.o: nukedata.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h filterdefs.h +osm.o: osm.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ + zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h xmlgeneric.h \ + avltree.h overlay.o: overlay.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h grtcirc.h ozi.o: ozi.c defs.h config.h queue.h gbtypes.h zlib/zlib.h zlib/zconf.h \ @@ -586,6 +614,7 @@ palmdoc.o: palmdoc.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ jeeps/gpsprot.h jeeps/gpscom.h jeeps/gpsfmt.h jeeps/gpsmath.h \ jeeps/gpsmem.h jeeps/gpsrqst.h jeeps/gpsinput.h jeeps/gpsproj.h \ pdbfile.h +parse.o: parse.c defs.h config.h queue.h gbtypes.h jeeps/gpsmath.h pathaway.o: pathaway.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h csv_util.h strptime.h \ pdbfile.h @@ -606,6 +635,9 @@ quovadis.o: quovadis.c quovadis.h defs.h config.h queue.h gbtypes.h \ pdbfile.h radius.o: radius.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h filterdefs.h grtcirc.h +random.o: random.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ + zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h filterdefs.h grtcirc.h \ + jeeps/gpsmath.h raymarine.o: raymarine.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h csv_util.h reverse_route.o: reverse_route.c defs.h config.h queue.h gbtypes.h \ @@ -692,6 +724,8 @@ vcf.o: vcf.c defs.h config.h queue.h gbtypes.h zlib/zlib.h zlib/zconf.h \ jeeps/gpsrqst.h jeeps/gpsinput.h jeeps/gpsproj.h vecs.o: vecs.c defs.h config.h queue.h gbtypes.h zlib/zlib.h zlib/zconf.h \ gbfile.h cet.h cet_util.h inifile.h csv_util.h +vidaone.o: vidaone.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ + zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h vitosmt.o: vitosmt.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h grtcirc.h vitovtt.o: vitovtt.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ @@ -715,6 +749,9 @@ xmlgeneric.o: xmlgeneric.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h xmlgeneric.h xmltag.o: xmltag.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h +xol.o:xol.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ + zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h xmlgeneric.h \ + jeeps/gpsmath.h garmin_tables.h yahoo.o: yahoo.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h xmlgeneric.h jeeps/gpsapp.o: jeeps/gpsapp.c jeeps/gps.h jeeps/../defs.h \ diff --git a/an1.c b/an1.c index e27603055..c499b12b4 100644 --- a/an1.c +++ b/an1.c @@ -27,8 +27,8 @@ #define MYNAME "an1" #include "defs.h" -static FILE *infile; -static FILE *outfile; +static gbfile *infile; +static gbfile *outfile; static char *output_type = NULL; static char *road_changes = NULL; @@ -89,94 +89,30 @@ typedef struct guid { #include "an1sym.h" -static unsigned short -ReadShort(FILE * f) -{ - gbuint16 result = 0; - - fread(&result, sizeof (result), 1, f); - return le_read16(&result); -} - -static void -WriteShort(FILE * f, unsigned short s) -{ - gbuint16 tmp = 0; - le_write16( &tmp, s ); - fwrite( &tmp, sizeof(tmp), 1, f ); -} - -static unsigned long -ReadLong(FILE * f) -{ - gbuint32 result = 0; - - fread(&result, sizeof (result), 1, f); - return le_read32(&result); -} - -static void -WriteLong(FILE * f, unsigned long l) -{ - gbuint32 tmp = 0; - le_write32( &tmp, l ); - - fwrite( &tmp, sizeof(tmp), 1, f ); -} - -static double -ReadDouble( FILE * f ) -{ - double tmp = 0; - double result = 0; - fread(&tmp, sizeof(tmp),1,f); - result = le_read_double( &tmp ); - return result; -} - -static void -WriteDouble(FILE * f, double d) -{ - double tmp = 0; - le_write_double( &tmp, d ); - fwrite( &tmp, sizeof(tmp), 1, f ); -} +#define ReadShort(f) gbfgetint16(f) +#define WriteShort(f,s) gbfputint16((s),f) +#define ReadLong(f) gbfgetint32(f) +#define WriteLong(f,l) gbfputint32((l),f) +#define ReadDouble(f) gbfgetdbl(f) +#define WriteDouble(f,d) gbfputdbl((d),f) static char * -ReadString( FILE * f, short len ) +ReadString( gbfile * f, short len ) { char *result = NULL; result = (char *)xcalloc( 1, len + 1 ); if ( len ) { - fread( result, 1, len, f ); - } - return result; -} - -static unsigned char -ReadChar( FILE *f ) -{ - unsigned char result = 0; - if (fread( &result, 1, 1, f ) < 1) { - fatal( MYNAME ": error reading an1 file. Perhaps this isn't really an an1 file."); + gbfread( result, 1, len, f ); } return result; } -static void -WriteChar( FILE *f, unsigned char c ) -{ - fwrite( &c, 1, 1, f ); -} - -static void -WriteString( FILE *f, char *s ) -{ - fwrite( s, 1, strlen(s), f ); -} +#define ReadChar(f) (unsigned char) gbfgetc(f) +#define WriteChar(f,c) gbfputc((unsigned char)(c),f) +#define WriteString(f,s) gbfputs((s),f) static void -ReadGuid( FILE *f, GUID *guid ) +ReadGuid( gbfile *f, GUID *guid ) { int i = 0; guid->l = ReadLong( f ); @@ -189,7 +125,7 @@ ReadGuid( FILE *f, GUID *guid ) } static void -WriteGuid( FILE *f, GUID *guid ) +WriteGuid( gbfile *f, GUID *guid ) { int i = 0; WriteLong( f, guid->l ); @@ -202,10 +138,10 @@ WriteGuid( FILE *f, GUID *guid ) } static void -Skip(FILE * f, +Skip(gbfile * f, unsigned long distance) { - fseek(f, distance, SEEK_CUR); + gbfseek(f, distance, SEEK_CUR); } static double @@ -386,7 +322,7 @@ static void Destroy_AN1_Symbol( an1_symbol_record *symbol ) { xfree( symbol->name ); } -static void Read_AN1_Waypoint( FILE *f, an1_waypoint_record *wpt ) { +static void Read_AN1_Waypoint( gbfile *f, an1_waypoint_record *wpt ) { short len; wpt->magic = ReadShort( f ); @@ -476,7 +412,7 @@ static void Read_AN1_Waypoint( FILE *f, an1_waypoint_record *wpt ) { wpt->fillflags = ReadLong( f ); } -static void Write_AN1_Waypoint( FILE *f, an1_waypoint_record *wpt ) { +static void Write_AN1_Waypoint( gbfile *f, an1_waypoint_record *wpt ) { short len; WriteShort( f, wpt->magic ); @@ -564,7 +500,7 @@ static void Write_AN1_Waypoint( FILE *f, an1_waypoint_record *wpt ) { WriteLong( f, wpt->fillflags ); } -static void Read_AN1_Vertex( FILE *f, an1_vertex_record *vertex ) { +static void Read_AN1_Vertex( gbfile *f, an1_vertex_record *vertex ) { vertex->magic = ReadShort( f ); vertex->unk0 = ReadLong( f ); @@ -573,7 +509,7 @@ static void Read_AN1_Vertex( FILE *f, an1_vertex_record *vertex ) { vertex->unk1 = ReadShort( f ); } -static void Write_AN1_Vertex( FILE *f, an1_vertex_record *vertex ) { +static void Write_AN1_Vertex( gbfile *f, an1_vertex_record *vertex ) { WriteShort( f, vertex->magic ); WriteLong( f, vertex->unk0 ); WriteLong( f, vertex->lon ); @@ -581,7 +517,7 @@ static void Write_AN1_Vertex( FILE *f, an1_vertex_record *vertex ) { WriteShort( f, vertex->unk1 ); } -static void Read_AN1_Line( FILE *f, an1_line_record *line ) { +static void Read_AN1_Line( gbfile *f, an1_line_record *line ) { short len; @@ -604,7 +540,7 @@ static void Read_AN1_Line( FILE *f, an1_line_record *line ) { line->pointcount = ReadLong( f ); } -static void Write_AN1_Line( FILE *f, an1_line_record *line ) { +static void Write_AN1_Line( gbfile *f, an1_line_record *line ) { short len; WriteLong( f, line->roadtype ); @@ -627,11 +563,11 @@ static void Write_AN1_Line( FILE *f, an1_line_record *line ) { WriteLong( f, line->pointcount ); } -static void Skip_AN1_IL( FILE *f ) { +static void Skip_AN1_IL( gbfile *f ) { Skip( f, 26 ); } -static void Skip_AN1_BM( FILE *f ) { +static void Skip_AN1_BM( gbfile *f ) { unsigned long bmsize; unsigned long palettesize; unsigned long bmisize; @@ -649,7 +585,7 @@ static void Skip_AN1_BM( FILE *f ) { Skip( f, bmsize + palettesize ); } -static void Read_AN1_Symbol( FILE *f, an1_symbol_record *symbol ) { +static void Read_AN1_Symbol( gbfile *f, an1_symbol_record *symbol ) { short len; /* This is just the high word of a long; we ate the low @@ -662,7 +598,7 @@ static void Read_AN1_Symbol( FILE *f, an1_symbol_record *symbol ) { symbol->name = ReadString( f, len ); } -static void Read_AN1_Header( FILE *f ) { +static void Read_AN1_Header( gbfile *f ) { unsigned short magic; unsigned short type; @@ -672,12 +608,12 @@ static void Read_AN1_Header( FILE *f ) { last_read_type = type; } -static void Write_AN1_Header( FILE *f ) { +static void Write_AN1_Header( gbfile *f ) { WriteShort( f, 11557 ); WriteShort( f, output_type_num ); } -static void Read_AN1_Bitmaps( FILE *f ) { +static void Read_AN1_Bitmaps( gbfile *f ) { long count; unsigned short magic; an1_symbol_record symbol; @@ -704,13 +640,13 @@ static void Read_AN1_Bitmaps( FILE *f ) { /* Read the symbol table */ } -static void Write_AN1_Bitmaps( FILE *f ) { +static void Write_AN1_Bitmaps( gbfile *f ) { /* On write, we don't output any bitmaps, so writing them * is just a matter of writing a count of zero */ WriteLong( f, 0 ); } -static void Read_AN1_Waypoints( FILE *f ) { +static void Read_AN1_Waypoints( gbfile *f ) { unsigned long count = 0; unsigned long i = 0; an1_waypoint_record *rec = NULL; @@ -839,13 +775,13 @@ Write_One_AN1_Waypoint( const waypoint *wpt ) } } -static void Write_AN1_Waypoints( FILE *f ) { +static void Write_AN1_Waypoints( gbfile *f ) { WriteShort( f, 2 ); WriteLong( f, waypt_count() ); waypt_disp_all( Write_One_AN1_Waypoint ); } -static void Read_AN1_Lines( FILE *f ) { +static void Read_AN1_Lines( gbfile *f ) { unsigned long count = 0; unsigned long i = 0; unsigned long j = 0; @@ -1026,7 +962,7 @@ Write_One_AN1_Vertex( const waypoint *wpt ) } } -static void Write_AN1_Lines( FILE *f ) { +static void Write_AN1_Lines( gbfile *f ) { WriteShort( f, 2 ); WriteLong( f, route_count()+track_count() ); @@ -1213,13 +1149,13 @@ Init_Road_Changes( void ) static void rd_init(const char *fname) { - infile = xfopen(fname, "rb", MYNAME); + infile = gbfopen_le(fname, "rb", MYNAME); } static void rd_deinit(void) { - fclose(infile); + gbfclose(infile); } static void @@ -1234,7 +1170,7 @@ my_read(void) static void wr_init(const char *fname) { - outfile = xfopen( fname, "wb", MYNAME ); + outfile = gbfopen_le( fname, "wb", MYNAME ); Init_Output_Type(); Init_Road_Changes(); opt_color_num = color_to_bbggrr(opt_color); @@ -1255,7 +1191,7 @@ static void wr_deinit( void ) { Free_Road_Changes(); - fclose(outfile); + gbfclose(outfile); } static void diff --git a/avltree.c b/avltree.c new file mode 100644 index 000000000..c90c5680f --- /dev/null +++ b/avltree.c @@ -0,0 +1,723 @@ +/* + + AVL tree implementation. + + Copyright (C) 2008 Olaf Klein, o.b.klein@gpsbabel.org + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + +*/ + +#include "avltree.h" + +#define MYNAME "avltree" + +#ifdef DEBUG_MEM +# define AVLTREE_MAGIC 0x41564c53 +/* ((((((0L | 'A') << 8) | 'V') << 8) | 'L') << 8) | 'T'; */ +#endif + +#ifdef MEM_DEBUG +void avltree_check_handle(const void *tree); +#endif +static void avltree_node_free(const avltree_t *tree, avlnode_t *node); +static int avltree_node_height(avlnode_t *node); +static int avltree_insert_node(avltree_t *tree, avlnode_t **root, const char *key, const void *data); +static int avltree_delete_node(avltree_t *tree, const char *key, avlnode_t **root, int *changed); +static avlnode_t *avltree_right_rotation(avlnode_t *A); +static avlnode_t *avltree_left_rotation(avlnode_t *A); +static avlnode_t *avltree_left_right_rotation(avlnode_t *A); +static avlnode_t *avltree_right_left_rotation(avlnode_t *A); +static avlnode_t *avltree_dupe_node(const avltree_t *tree, const avlnode_t *node); +static int avltree_strcmpr(const char *s1, const char *s2); +static int avltree_case_ignore_strcmpr(const char *s1, const char *s2); +static avlnode_t *avltree_find_next(const avltree_t *tree, avlnode_t *node, const char *key); +static void avltree_save_key(avltree_t *tree, const char *key); + + +#ifdef MEM_DEBUG +# define AVLTREE_CHECK_HANDLE(a) avltree_valid_tree(a) +#else +# define AVLTREE_CHECK_HANDLE(a) +#endif + +#define AVLTREE_INVALID_BALANCE "%s/%s.%d: Invalid balance %d at node \"%s\"!\n", \ + tree->module, MYNAME, __LINE__, node->balance, node->key + + +/* Allocate and initialize an AVL Tree */ + +avltree_t * +avltree_init(const int options, const char *module) +{ + avltree_t *tree; + + if ((module == NULL) || (*module == '\0')) + fatal(MYNAME ": 'avltree_init' should be called with a valid module name!\n"); + + tree = xcalloc(1, sizeof(*tree)); + tree->options = options; + tree->module = module; + + if (options & AVLTREE_NON_CASE_SENSITIVE) { + if (options & AVLTREE_DESCENDING) + tree->compare = avltree_case_ignore_strcmpr; /* descending, non-case-sensitive */ + else + tree->compare = case_ignore_strcmp; /* ascending, non-case-sensitive */ + } + else { + if (options & AVLTREE_DESCENDING) + tree->compare = avltree_strcmpr; /* descending, case-sensitive */ + else + tree->compare = strcmp; /* ascending, case-sensitive */ + } + + return tree; +} + + +/* Destroy an AVL Tree */ + +void +avltree_done(avltree_t *tree) +{ + AVLTREE_CHECK_HANDLE(tree); + + avltree_save_key(tree, NULL); + if (tree->count) + avltree_node_free(tree, tree->root); + xfree(tree); +} + + +/* Get number of items in tree */ + +int +avltree_count(const avltree_t *tree) +{ + AVLTREE_CHECK_HANDLE(tree); + + return tree->count; +} + + +/* Delete item with key [key] */ + +int +avltree_delete(avltree_t *tree, const char *key) +{ + int changed = 0; + + AVLTREE_CHECK_HANDLE(tree); + + if (key == NULL) + fatal("%s/%s.%d: Attempt to delete a NULL-pointer!\n", + tree->module, MYNAME, __LINE__); + + return avltree_delete_node(tree, key, &tree->root, &changed); +} + + +/* Duplicate an existing tree */ + +avltree_t * +avltree_dupe(const avltree_t *tree, const char *module) +{ + avltree_t *dupe; + + AVLTREE_CHECK_HANDLE(tree); + + dupe = avltree_init(tree->options, module); + if ((dupe->count = tree->count)) + dupe->root = avltree_dupe_node(tree, tree->root); + + return dupe; +} + + +/* Find key [key] in tree */ + +int +avltree_find(const avltree_t *tree, const char *key, const void **data) +{ + avlnode_t *node; + + AVLTREE_CHECK_HANDLE(tree); + + node = tree->root; + while (node) { + int compare = tree->compare(key, node->key); + + if (compare < 0) + node = node->left; + else if (compare > 0) + node = node->right; + else { + if (data) + (*data) = node->data; + break; + } + } + + return (node) ? 1 : 0; +} + + +/* Get the first (the MIN-) entry of the tree */ + +const char * +avltree_first(const avltree_t *tree, const void **data) +{ + return avltree_next(tree, NULL, data); +} + + +/* Get the current height of the tree */ + +int +avltree_height(const avltree_t *tree) +{ + AVLTREE_CHECK_HANDLE(tree); + + if (tree->count) + return avltree_node_height(tree->root); + else + return 0; +} + + +/* Insert key [key] and [data] into tree */ + +int +avltree_insert(avltree_t *tree, const char *key, const void *data) +{ + int count; + + AVLTREE_CHECK_HANDLE(tree); + + if (key == NULL) + fatal("%s/%s.%d: Attempt to insert a NULL-pointer!\n", + tree->module, MYNAME, __LINE__); + + count = tree->count; + avltree_insert_node(tree, &tree->root, key, data); + return (count != tree->count) ? 1 : 0; +} + + +/* Get the next (the entry above [key]) */ + +const char * +avltree_next(const avltree_t *tree, const char *key, const void **data) +{ + avlnode_t *node; + + AVLTREE_CHECK_HANDLE(tree); + + if (key == NULL) + fatal("%s/%s.%d: Attempt to look for a NULL-pointer!\n", + tree->module, MYNAME, __LINE__); + + node = tree->root; + if (! node) return NULL; + + if ((node = avltree_find_next(tree, node, key))) { + avltree_save_key((avltree_t *)tree, node->key); + if (data) + (*data) = node->data; + } + else + avltree_save_key((avltree_t *)tree, NULL); + + return tree->key; +} + + +/* ------------------------------ static stuff ------------------------------ */ + + +#ifdef MEM_DEBUG + +void +avltree_check_handle(const avltree_t *tree) +{ + if (! tree) + fatal(MYNAME ": Invalid (NULL-) pointer!\n"); + if (tree->magic != AVLTREE_MAGIC) + fatal(MYNAME ": Invalid (no AVL tree object) pointer!\n"); +} + +#endif + + +static void +avltree_node_free(const avltree_t *tree, avlnode_t *node) +{ + if ((! (tree->options & AVLTREE_STATIC_KEYS)) && node->key) + xfree((char *)node->key); + if (node->left) + avltree_node_free(tree, node->left); + if (node->right) + avltree_node_free(tree, node->right); + xfree(node); +} + + +static int +avltree_node_height(avlnode_t *node) +{ + int height = 1; + + if (node->balance < 0) + height += avltree_node_height(node->left); + else if (node->right) + height += avltree_node_height(node->right); + + return height; +} + + +static avlnode_t * +avltree_right_rotation(avlnode_t *A) +{ +/* +> A B +> / \ / \ +> \ / \ +> B -->> A . +> / \ / \ / \ +> \ +> . +> / \ +*/ + avlnode_t *B; + + B = A->right; + A->right = B->left; + B->left = A; + + /* update balance of all touched nodes */ + /* reference: */ + + B->balance--; + A->balance = -(B->balance); + + return B; +} + + +static avlnode_t * +avltree_left_rotation(avlnode_t *A) +{ +/* +> A B +> / \ / \ +> / / \ +> B -->> . A +> / \ / \ / \ +> / +> . +> / \ +*/ + avlnode_t *B; + + B = A->left; + A->left = B->right; + B->right = A; + + /* update balance of all touched nodes */ + /* reference: */ + + B->balance++; + A->balance = -(B->balance); + + return B; +} + + +static avlnode_t * +avltree_left_right_rotation(avlnode_t *A) +{ +/* +> A C +> / \ / \ +> / / \ +> B -->> B A +> / \ / \ / \ +> \ +> C +*/ + avlnode_t *B, *C; + + B = A->left; + C = B->right; + A->left = C->right; + B->right = C->left; + C->right = A; + C->left = B; + + /* update balance of all touched nodes */ + /* reference: */ + + A->balance = (C->balance > 0) ? 0 : -(C->balance); + B->balance = (C->balance < 0) ? 0 : -(C->balance); + C->balance = 0; + + return C; +} + + +static avlnode_t * +avltree_right_left_rotation(avlnode_t *A) +{ +/* +> A C +> / \ / \ +> \ / \ +> B -->> B A +> / \ / \ / \ +> / +> C +*/ + avlnode_t *B, *C; + + B = A->right; + C = B->left; + A->right = C->left; + B->left = C->right; + C->left = A; + C->right = B; + + /* update balance of all touched nodes */ + /* reference: */ + + A->balance = (C->balance < 0) ? 0 : -(C->balance); + B->balance = (C->balance > 0) ? 0 : -(C->balance); + C->balance = 0; + + return C; +} + + +static int +avltree_insert_node(avltree_t *tree, avlnode_t **root, const char *key, const void *data) +{ + int changed = 0; + int compare; + avlnode_t *node = (*root); + + if (node == NULL) { + (*root) = node = xcalloc(1, sizeof(*node)); + if (tree->options & AVLTREE_STATIC_KEYS) + node->key = key; + else + node->key = xstrdup(key); + node->data = data; + tree->count++; + return 1; /* anyway, our tree has been changed */ + } + + compare = tree->compare(key, node->key); + + if (compare < 0) { + if (avltree_insert_node(tree, &node->left, key, data)) { + changed = (--node->balance != 0); + switch(node->balance) { + case -2: + if (node->left->balance < 0) + node = avltree_left_rotation(node); + else + node = avltree_left_right_rotation(node); + (*root) = node; + case 0: + changed = 0; + case -1: + break; + default: + /* should be impossible :-) */ + fatal(AVLTREE_INVALID_BALANCE); + } + } + else + changed = 0; + } + else if (compare > 0) { + if (avltree_insert_node(tree, &node->right, key, data)) { + changed = (++node->balance != 0); + switch(node->balance) { + case +2: + if (node->right->balance > 0) + node = avltree_right_rotation(node); + else + node = avltree_right_left_rotation(node); + (*root) = node; + case 0: + changed = 0; + case +1: + break; + default: + /* should be impossible :-) */ + fatal(AVLTREE_INVALID_BALANCE); + } + } + else + changed = 0; + } + else { + if (tree->options & AVLTREE_PARANOIAC) + fatal("%s/%s.%d: Duplicate keys are not allowed (\"%s\")!\n", + tree->module, MYNAME, __LINE__, key); + changed = 0; + } + + return changed; +} + + + +static int +avltree_delete_node(avltree_t *tree, const char *key, avlnode_t **root, int *changed) +{ + avlnode_t *node = (*root); + int deleted = 0; + int compare; + + if (node == NULL) { + if (tree->options & AVLTREE_PARANOIAC) + fatal("%s/%s.%d: Key to delete \"%s\" not found!\n", + tree->module, MYNAME, __LINE__, key); + return 0; + } + + compare = tree->compare(key, node->key); + + if (compare < 0) { + deleted = avltree_delete_node(tree, key, &node->left, changed); + if (*changed) { + node->balance++; /* shift weight to right */ + switch(node->balance) { + case +1: + (*changed) = 0; /* stop rebalancing */ + case 0: + break; + case +2: + if (node->right->balance >= 0) + node = avltree_right_rotation(node); + else + node = avltree_right_left_rotation(node); + (*root) = node; + if (node->balance == -1) + (*changed) = 0; + break; + default: + /* should be impossible :-) */ + fatal(AVLTREE_INVALID_BALANCE); + } + } + } + else if (compare > 0) { + deleted = avltree_delete_node(tree, key, &node->right, changed); + if (*changed) { + node->balance--; /* shift weight to left */ + switch(node->balance) { + case -1: + (*changed) = 0; /* stop rebalancing */ + case 0: + break; + case -2: + if (node->left->balance <= 0) + node = avltree_left_rotation(node); + else + node = avltree_left_right_rotation(node); + (*root) = node; + if (node->balance == +1) + (*changed) = 0; + break; + default: + /* should be impossible :-) */ + fatal(AVLTREE_INVALID_BALANCE); + } + } + } + else { + if (node->left) { + if (node->right) { + const char *temp_key; + const void *temp_data; + avlnode_t *succ = node->right; + + while (succ->left) succ = succ->left; /* find successor */ + + temp_key = succ->key; /* swap contents */ + temp_data = succ->data; + succ->key = node->key; + succ->data = node->data; + node->key = temp_key; + node->data = temp_data; + + deleted = avltree_delete_node(tree, key, &node->right, changed); + + if (*changed) { + node->balance--; /* shift weight to left */ + switch(node->balance) { + case -1: + (*changed) = 0; /* stop rebalancing */ + case 0: + break; + case -2: + if (node->left->balance <= 0) + node = avltree_left_rotation(node); + else + node = avltree_left_right_rotation(node); + (*root) = node; + if (node->balance == +1) + (*changed) = 0; + break; + default: + /* should be impossible :-) */ + fatal(AVLTREE_INVALID_BALANCE); + } + } + return deleted; + } + else { /* only left branch */ + (*root) = node->left; + node->left = NULL; + } + } + else if (node->right) { /* only right branch */ + (*root) = node->right; + node->right = NULL; + } + else /* only a simple leaf */ + (*root) = NULL; + + avltree_node_free(tree, node); + tree->count--; + (*changed) = 1; + deleted = 1; + } + + return deleted; +} + + +static avlnode_t * +avltree_dupe_node(const avltree_t *tree, const avlnode_t *node) +{ + avlnode_t *res = xcalloc(1, sizeof(*res)); + + if (tree->options & AVLTREE_STATIC_KEYS) + res->key = node->key; + else + res->key = xstrdup(node->key); + + res->balance = node->balance; + if (node->left) + res->left = avltree_dupe_node(tree, node->left); + if (node->right) + res->right = avltree_dupe_node(tree, node->right); + + return res; +} + + +static int +avltree_strcmpr(const char *s1, const char *s2) +{ + return -(strcmp(s1, s2)); +} + + +static int +avltree_case_ignore_strcmpr(const char *s1, const char *s2) +{ + return -(case_ignore_strcmp(s1, s2)); +} + + +static avlnode_t * +avltree_find_next(const avltree_t *tree, avlnode_t *node, const char *key) +{ + avlnode_t *prev = NULL; + + if (key == NULL) { + if ((node = tree->root)) { + while (node->left) + node = node->left; + } + return node; + } + + while (node) { + int compare = tree->compare(key, node->key); + + if (compare < 0) { + prev = node; + node = node->left; + } + else if (compare > 0) + node = node->right; + else { + if ((node = node->right)) + while (node->left) node = node->left; + else + node = prev; + return node; + } + } + /* The previous node was deleted and we could not find it. */ + return prev; +} + + +/* + Save [key] for a possible delete before next op. Now we have no problem with: + + curr = NULL; + while ((curr = avtree_next(tree, curr, NULL))) { + avltree_delete(tree, curr); + } + */ +static void +avltree_save_key(avltree_t *tree, const char *key) +{ + if (tree->options & AVLTREE_STATIC_KEYS) + tree->key = key; + else { + if (key == NULL) { + if (tree->key_sz) { + xfree((char *)tree->key); + tree->key_sz = 0; + } + tree->key = NULL; + } + else { + int n, n8; + + n = strlen(key) + 1; + n8 = ((n + 7) / 8) * 8; + + if (n8 > tree->key_sz) { + if (tree->key_sz == 0) + tree->key = xmalloc(n8); + else + tree->key = xrealloc((char *)tree->key, n8); + tree->key_sz = n8; + } + strncpy((char *)tree->key, key, n); + } + } +} diff --git a/avltree.h b/avltree.h new file mode 100644 index 000000000..d8c9ddb4e --- /dev/null +++ b/avltree.h @@ -0,0 +1,94 @@ +/* + + AVL tree implementation. + + Copyright (C) 2008 Olaf Klein, o.b.klein@gpsbabel.org + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + +*/ + +#ifndef AVLTREE_H_INCLUDED +#define AVLTREE_H_INCLUDED + +#include "defs.h" +#include +#include + +typedef int (*avltree_compare_cb) (const char *, const char *); + +typedef struct avltree_s +{ +#ifdef MEM_DEBUG + const int magic; +#endif + struct avlnode_s *root; + const char *module; + int count; /* number of items in tree */ + int options; + const char *key; + int key_sz; + avltree_compare_cb compare; +} avltree_t; + +typedef struct avlnode_s { + int balance; + const char *key; + const void *data; + struct avlnode_s *left; + struct avlnode_s *right; +} avlnode_t; + +/* options for avltree_init */ + +#define AVLTREE_ASCENDING 0 /* default */ +#define AVLTREE_DESCENDING 1 +#define AVLTREE_CASE_SENSITIVE 0 /* default */ +#define AVLTREE_NON_CASE_SENSITIVE 2 +#define AVLTREE_STATIC_KEYS 128 +#define AVLTREE_PARANOIAC 256 /* STOP on "duplicate key" (insert) or on "not found" (delete) */ + +/* Allocate and initialize an AVL Tree */ +avltree_t *avltree_init(const int options, const char *module); + +/* Destroy an AVL Tree */ +void avltree_done(avltree_t *tree); + +/* Get number of items in tree */ +int avltree_count(const avltree_t *tree); + +/* Delete item with key [key] */ +int avltree_delete(avltree_t *tree, const char *key); + +/* Duplicate an existing tree */ +avltree_t *avltree_dupe(const avltree_t *tree, const char *module); + +/* Find key [key] in tree */ +int avltree_find(const avltree_t *tree, const char *key, const void **data); + +/* Get the first (the MIN-) entry of the tree */ +const char *avltree_first(const avltree_t *tree, const void **data); + +/* Get the current height of the tree */ +int avltree_height(const avltree_t *tree); + +/* Insert key [key] and [data] into tree */ +int avltree_insert(avltree_t *tree, const char *key, const void *data); + +/* Get the next (the entry above [key]) */ +const char *avltree_next(const avltree_t *tree, const char *key, const void **data); + + +#endif /* AVLTREE_H_INCLUDED */ diff --git a/axim_gpb.c b/axim_gpb.c index 6d083cee8..a931ba033 100644 --- a/axim_gpb.c +++ b/axim_gpb.c @@ -104,8 +104,8 @@ decode_buff(const char *buff, route_head *track) (tm.tm_hour > 23) || (tm.tm_min > 60) || (tm.tm_sec > 60), MYNAME ": Invalid or unsupported file (invalid time-stamp)."); is_fatal( - (fabs(wpt->latitude) > 180) || - (fabs(wpt->longitude) > 90), + (fabs(wpt->latitude) > 90) || + (fabs(wpt->longitude) > 180), MYNAME ": Invalid or unsupported file (lat or/and lon out of range)."); /* post work */ diff --git a/bcr.c b/bcr.c index c9eaf340e..0be68f4f8 100644 --- a/bcr.c +++ b/bcr.c @@ -298,7 +298,12 @@ bcr_data_read(void) route_add_wpt(route, wpt); } - bcr_create_waypts_from_route(route); + + /* remove empty route */ + if (route->rte_waypt_ct == 0) + route_del_head(route); + else + bcr_create_waypts_from_route(route); } /* %%% bcr write support %%% ----------------------------------- */ diff --git a/cet_util.c b/cet_util.c index 19e76f24d..d8fd3930f 100644 --- a/cet_util.c +++ b/cet_util.c @@ -1154,38 +1154,30 @@ cet_disp_character_set_names(FILE *fout) int cet_gbfprintf(gbfile *stream, const cet_cs_vec_t *src_vec, const char *fmt, ...) { - char buff[128]; - int res, ct; + int res; + char *cout; va_list args; - char *cout = buff; va_start(args, fmt); - ct = vsnprintf(buff, sizeof(buff), fmt, args); + xvasprintf(&cout, fmt, args); va_end(args); - if (ct >= (int)sizeof(buff)) { - cout = xmalloc(ct + 1); - va_start(args, fmt); - vsnprintf(cout, ct + 1, fmt, args); - va_end(args); - } - if (global_opts.charset != src_vec) { if (src_vec != &cet_cs_vec_utf8) { char *ctemp = cet_str_any_to_utf8(cout, src_vec); - if (cout != buff) xfree(cout); + xfree(cout); cout = ctemp; } if (global_opts.charset != &cet_cs_vec_utf8) { char *ctemp = cet_str_utf8_to_any(cout, global_opts.charset); - if (cout != buff) xfree(cout); + xfree(cout); cout = ctemp; } } res = gbfprintf(stream, "%s", cout); - if (cout != buff) xfree(cout); + xfree(cout); return res; } diff --git a/cetus.c b/cetus.c index 8617a2995..138625966 100644 --- a/cetus.c +++ b/cetus.c @@ -1,7 +1,7 @@ /* Read and write Cetus files. - Copyright (C) 2002 Robert Lipe, robertlipe@usa.net + Copyright (C) 2002-2008 Robert Lipe, robertlipe@usa.net This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -124,7 +124,7 @@ typedef struct cetus_track_point_s char hour; char min; char sec; - char msec; + char dsec; char sat; char hdop; pdb_32 latitude; @@ -181,17 +181,19 @@ read_track_point(cetus_track_point_t *data, const time_t basetime) i = be_read16(&data->course); if (i != 4000) WAYPT_SET(wpt, course, (float) i / 10); - switch(data->hour / 32) /* extract fix */ + switch(data->hour >> 5) /* extract fix */ { - case 0: break; /* no GPS */ case 1: wpt->fix = fix_none; break; case 2: wpt->fix = fix_2d; break; case 3: wpt->fix = fix_3d; break; case 4: wpt->fix = fix_dgps; break; + default: break; /* no GPS */ } wpt->creation_time = basetime + - ((data->hour % 32) * 3600) + (data->min * 60) + data->sec; + ((data->hour & 0x1F) * 3600) + (data->min * 60) + data->sec; + if (data->dsec) + wpt->microseconds = (int)data->dsec * 10000; return wpt; } @@ -205,7 +207,7 @@ read_tracks(const pdbfile *pdb) char descr[(2 * TRACK_POINT_SIZE) + 1]; char temp_descr[TRACK_POINT_SIZE + 1]; cetus_track_head_t *head; - waypoint *wpt, *prev; + waypoint *wpt; route_head *track; time_t basetime; @@ -230,7 +232,6 @@ read_tracks(const pdbfile *pdb) records = reclen / TRACK_POINT_SIZE; c += 8; - prev = NULL; for (i = 0; i < records; i++, c += TRACK_POINT_SIZE) { @@ -240,7 +241,8 @@ read_tracks(const pdbfile *pdb) case 0: /* track header */ head = (cetus_track_head_t *)c; - if (head->id[0] != 'C' || head->id[1] != 'G') fatal(MYNAME ": Invalid track header!\n"); + if (head->id[0] != 'C' || head->id[1] != 'G') + fatal(MYNAME ": Invalid track header!\n"); memset(&tm, 0, sizeof(tm)); tm.tm_mday = head->day; @@ -266,14 +268,6 @@ read_tracks(const pdbfile *pdb) { track_add_wpt(track, wpt); points++; - - /* Did we run over midnight ? */ - if ((prev != NULL) && (prev->creation_time > wpt->creation_time)) - { - basetime += (24 * 3600); - wpt->creation_time += (24 * 3600); - } - prev = wpt; } else dropped++; @@ -400,18 +394,16 @@ wr_deinit(void) static void data_read(void) { - pdbfile *pdb = file_in; - - if (pdb->creator != MYCREATOR) fatal(MYNAME ": Not a Cetus file.\n"); + if (file_in->creator != MYCREATOR) fatal(MYNAME ": Not a Cetus file.\n"); - switch(pdb->type) + switch(file_in->type) { case MYTYPE_TRK: - read_tracks(pdb); + read_tracks(file_in); break; case MYTYPE_WPT: - read_waypts(pdb); + read_waypts(file_in); break; } } @@ -425,6 +417,7 @@ cetus_writewpt(const waypoint *wpt) char *vdata; char *desc_long; char *desc_short; + char *desc_geo; char *desc; rec = xcalloc(sizeof(*rec)+18 + NOTESZ + DESCSZ,1); @@ -480,9 +473,24 @@ cetus_writewpt(const waypoint *wpt) } vdata += strlen( vdata ) + 1; + if (wpt->gc_data.diff) { + xasprintf(&desc_geo, "%s%s by %s\n%.4s/%.4s %3.1f/%3.1f\n", + wpt->gc_data.is_available==status_true ? + "" : " (Disabled)", + wpt->gc_data.is_archived==status_true ? + " (Archived)" : "", + wpt->gc_data.placer, + gs_get_cachetype(wpt->gc_data.type), + gs_get_container(wpt->gc_data.container), + wpt->gc_data.diff/10.0, + wpt->gc_data.terr/10.0); + } else { + desc_geo = xstrdup(""); + } + if (wpt->gc_data.desc_short.utfstring) { char *stripped_html = strip_html(&wpt->gc_data.desc_short); - desc_short = xstrdup("\n\n"); + desc_short = xstrdup(wpt->gc_data.diff == 0 ? "\n\n" : ""); desc_short = xstrappend(desc_short, xstrdup(stripped_html)); xfree(stripped_html); } else { @@ -501,12 +509,14 @@ cetus_writewpt(const waypoint *wpt) desc = wpt->description ? xstrdup(wpt->description) : xstrdup(""); - snprintf(vdata, DESCSZ, "%s%s%s", + snprintf(vdata, DESCSZ, "%s%s%s%s", desc, + desc_geo, desc_short, desc_long); xfree(desc); + xfree(desc_geo); xfree(desc_short); xfree(desc_long); diff --git a/chkdoc b/chkdoc index f16444efd..d57a2b7a8 100755 --- a/chkdoc +++ b/chkdoc @@ -12,7 +12,7 @@ checkit() { ECODE=1 fi - if ! grep -qi $TYPE ~/src/babelweb/changes.html + if ! grep -qi $TYPE ~/src/babelweb/changes*.html then echo $STY $TYPE is not documented in changes.html. ECODE=1 diff --git a/config.h.in b/config.h.in index 0e668d4f0..ff1bfe607 100644 --- a/config.h.in +++ b/config.h.in @@ -27,6 +27,18 @@ /* Define to 1 if you have the `sleep' function. */ #undef HAVE_SLEEP +/* Define if we have va_copy */ +#undef HAVE_VA_COPY + +/* Define if we have __va_copy */ +#undef HAVE___VA_COPY + +/* Define as 1 if your va_list type is an array */ +#undef HAVE_VA_LIST_AS_ARRAY + +/* 1 to enable as many formats as possible */ +#undef MAXIMAL_ENABLED + /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT diff --git a/configure b/configure index d51b46141..ba89b6b49 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.61 for GPSBabel 1.3.4. +# Generated by GNU Autoconf 2.61 for GPSBabel 1.3.5. # # Report bugs to . # @@ -574,8 +574,8 @@ SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='GPSBabel' PACKAGE_TARNAME='gpsbabel' -PACKAGE_VERSION='1.3.4' -PACKAGE_STRING='GPSBabel 1.3.4' +PACKAGE_VERSION='1.3.5' +PACKAGE_STRING='GPSBabel 1.3.5' PACKAGE_BUGREPORT='BUG-REPORT-ADDRESS' # Factoring default headers for most tests. @@ -652,9 +652,11 @@ build_alias host_alias target_alias PACKAGE_RELEASE +DOCVERSION GBMAJOR GBMINOR GBMICRO +GBBUILD build build_cpu build_vendor @@ -683,6 +685,7 @@ CPP GREP EGREP PALM_DB_CMT +FMTS FILEINFO RC LIBUSBCONFIG @@ -1210,7 +1213,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures GPSBabel 1.3.4 to adapt to many kinds of systems. +\`configure' configures GPSBabel 1.3.5 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1276,7 +1279,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of GPSBabel 1.3.4:";; + short | recursive ) echo "Configuration of GPSBabel 1.3.5:";; esac cat <<\_ACEOF @@ -1286,6 +1289,7 @@ Optional Features: --enable-shapefile=(yes)|no --enable-pdb=(yes)|no --enable-csv=(yes)|no + --enable-most=(yes)|no --enable-filters=(yes)|no --enable-efence=yes|(no) @@ -1372,7 +1376,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -GPSBabel configure 1.3.4 +GPSBabel configure 1.3.5 generated by GNU Autoconf 2.61 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, @@ -1386,7 +1390,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by GPSBabel $as_me 1.3.4, which was +It was created by GPSBabel $as_me 1.3.5, which was generated by GNU Autoconf 2.61. Invocation command line was $ $0 $@ @@ -1739,9 +1743,10 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu - +# Increase GBBUILD for a new release +GBBUILD=16 # YYYYMMDD, please, if beta, i.e. "-beta20060413" -# PACKAGE_RELEASE="-beta20070711" +# PACKAGE_RELEASE="-beta20080305" cat >>confdefs.h <<_ACEOF #define PACKAGE_RELEASE "$PACKAGE_RELEASE" @@ -1749,6 +1754,11 @@ _ACEOF +DOCVERSION=`echo $PACKAGE_VERSION` +DOCVERSION=development +DOCVERSION=1.3.5 + + GBMAJOR=`echo $PACKAGE_VERSION | (IFS="."; read major minor micro; echo $major)` GBMINOR=`echo $PACKAGE_VERSION | (IFS="."; read major minor micro; echo $minor)` GBMICRO=`echo $PACKAGE_VERSION | (IFS="."; read major minor micro; echo $micro)` @@ -1756,6 +1766,7 @@ GBMICRO=`echo $PACKAGE_VERSION | (IFS="."; read major minor micro; echo $micro)` + # AC_CONFIG_SRCDIR([nmea.c]) ac_config_headers="$ac_config_headers config.h" @@ -3993,6 +4004,31 @@ echo "${ECHO_T}yes" >&6; } echo "${ECHO_T}no" >&6; } fi +{ echo "$as_me:$LINENO: checking whether to support maximum number of formats" >&5 +echo $ECHO_N "checking whether to support maximum number of formats... $ECHO_C" >&6; } +# Check whether --enable-most was given. +if test "${enable_most+set}" = set; then + enableval=$enable_most; enable_most="$enableval" +else + enable_most="yes" +fi + + if test "$enable_most" != "no" ; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +cat >>confdefs.h <<\_ACEOF +#define MAXIMAL_ENABLED 1 +_ACEOF + + FMTS='$(ALL_FMTS)' + else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + FMTS='$(MINIMAL_FMTS)' + fi + + { echo "$as_me:$LINENO: checking whether to support filters" >&5 echo $ECHO_N "checking whether to support filters... $ECHO_C" >&6; } # Check whether --enable-filters was given. @@ -4275,9 +4311,15 @@ fi USB_LIBS="`libusb-config --prefix`/lib/libusb.a -framework IOKit -framework CoreFoundation" LDFLAGS=$OLDFLAGS CDFLAGS=$OCDFLAGS + OSJEEPS=jeeps/gpslibusb.o + else + OSJEEPS=jeeps/gpsusbstub.o fi + ;; + *) + OSJEEPS=jeeps/gpslibusb.o + ;; esac - OSJEEPS=jeeps/gpslibusb.o CFLAGS="$OCFLAGS" # LIBS="$LIBS `libusb-config --libs`" else @@ -4305,7 +4347,9 @@ if test "${with_expathdr+set}" = set; then else case "$target" in - *-*-darwin*) + *-*-darwin6*|*-*-darwin7*|*-*-darwin8*) + # Restrict test to OS/X 10.4 and earlier. Leopard (10.5) + # provides expat and in a sensible location. if test -f /sw/include/expat.h ; then xpathdr=/sw/include/ fi @@ -4331,15 +4375,49 @@ echo $ECHO_N "checking for libexpat... $ECHO_C" >&6; } # Check whether --with-libexpat was given. if test "${with_libexpat+set}" = set; then - withval=$with_libexpat; CFLAGS="$CFLAGS -L$withval" - EXPAT_LIB="-L$withval -lexpat" + withval=$with_libexpat; + # If the developer specified a reference + # to a FILE and not a directory, assume they are a highly + # trained professional that has specified a .a to to be used. + if test -f $withval ; then + EXPAT_LIB=$withval + else + CFLAGS="$CFLAGS -L$withval" + EXPAT_LIB="-L$withval -lexpat" + fi else case "$target" in - *-*-darwin*) + *-*-darwin6*|*-*-darwin7*|*-*-darwin8*) + # Restrict test to OS/X 10.4 and earlier. Leopard (10.5) + # provides expat and in a sensible location. if test -f /sw/lib/libexpat.a ; then + # libexpat installed via fink EXPAT_LIB=/sw/lib/libexpat.a + LIBS="$LIBS -L/sw/lib" + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LIBEXPAT 1 +_ACEOF + + + fi + if test -f /opt/local/lib/libexpat.a ; then + # libexpat installed via macports + EXPAT_LIB=/opt/local/lib/libexpat.a + LIBS="$LIBS -L/opt/local/lib" + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LIBEXPAT 1 +_ACEOF + + + fi + if test -f /usr/local/lib/libexpat.a ; then + # libexpat installed from source + EXPAT_LIB=/usr/local/lib/libexpat.a + LIBS="$LIBS -L/usr/local/lib" cat >>confdefs.h <<\_ACEOF #define HAVE_LIBEXPAT 1 @@ -4591,6 +4669,212 @@ fi done +# +# Checks for how the system handles va_list +# paul.bromiley@man.ac.uk +# +{ echo "$as_me:$LINENO: checking for va_copy" >&5 +echo $ECHO_N "checking for va_copy... $ECHO_C" >&6; } +if test "${ac_cv_c_va_copy+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +va_list ap1, ap2; + va_copy(ap1,ap2); + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_c_va_copy="yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_c_va_copy="no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_va_copy" >&5 +echo "${ECHO_T}$ac_cv_c_va_copy" >&6; } +if test "$ac_cv_c_va_copy" = "yes" +then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_VA_COPY 1 +_ACEOF + +fi +{ echo "$as_me:$LINENO: checking for __va_copy" >&5 +echo $ECHO_N "checking for __va_copy... $ECHO_C" >&6; } +if test "${ac_cv_c___va_copy+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +va_list ap1, ap2; + __va_copy(ap1,ap2); + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_c___va_copy="yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_c___va_copy="no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c___va_copy" >&5 +echo "${ECHO_T}$ac_cv_c___va_copy" >&6; } +if test "$ac_cv_c___va_copy" = "yes" +then + +cat >>confdefs.h <<\_ACEOF +#define HAVE___VA_COPY 1 +_ACEOF + +fi + +# +# Does this platform require array notation to assign to a va_list? +# +{ echo "$as_me:$LINENO: checking va_list assignments need array notation" >&5 +echo $ECHO_N "checking va_list assignments need array notation... $ECHO_C" >&6; } +if test "${ac_cv_valistisarray+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + ac_cv_valistisarray=false +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + #include + void foo(int i, ...) { + va_list ap1, ap2; + va_start(ap1, i); + ap2 = ap1; + if (va_arg(ap2, int) != 123 || va_arg(ap1, int) != 123) { exit(1); } + va_end(ap1); va_end(ap2); + } + int main() + { foo(0, 123); return(0); } +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_valistisarray=false +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_valistisarray=true +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi + + +if test "$ac_cv_valistisarray" = true ; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_VA_LIST_AS_ARRAY 1 +_ACEOF + + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi ac_config_files="$ac_config_files Makefile gbversion.h xmldoc/makedoc tools/mkcapabilities win32/gpsbabel.rc jeeps/Makefile shapelib/Makefile zlib/empty" cat >confcache <<\_ACEOF @@ -4989,7 +5273,7 @@ exec 6>&1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by GPSBabel $as_me 1.3.4, which was +This file was extended by GPSBabel $as_me 1.3.5, which was generated by GNU Autoconf 2.61. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -5038,7 +5322,7 @@ Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ -GPSBabel config.status 1.3.4 +GPSBabel config.status 1.3.5 configured by $0, generated by GNU Autoconf 2.61, with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" @@ -5254,9 +5538,11 @@ build_alias!$build_alias$ac_delim host_alias!$host_alias$ac_delim target_alias!$target_alias$ac_delim PACKAGE_RELEASE!$PACKAGE_RELEASE$ac_delim +DOCVERSION!$DOCVERSION$ac_delim GBMAJOR!$GBMAJOR$ac_delim GBMINOR!$GBMINOR$ac_delim GBMICRO!$GBMICRO$ac_delim +GBBUILD!$GBBUILD$ac_delim build!$build$ac_delim build_cpu!$build_cpu$ac_delim build_vendor!$build_vendor$ac_delim @@ -5284,6 +5570,7 @@ CPP!$CPP$ac_delim GREP!$GREP$ac_delim EGREP!$EGREP$ac_delim PALM_DB_CMT!$PALM_DB_CMT$ac_delim +FMTS!$FMTS$ac_delim FILEINFO!$FILEINFO$ac_delim RC!$RC$ac_delim LIBUSBCONFIG!$LIBUSBCONFIG$ac_delim @@ -5301,7 +5588,7 @@ LIBOBJS!$LIBOBJS$ac_delim LTLIBOBJS!$LTLIBOBJS$ac_delim _ACEOF - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 83; then + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 86; then break elif $ac_last_try; then { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 @@ -5730,3 +6017,4 @@ if test "$no_create" != yes; then $ac_cs_success || { (exit 1); exit 1; } fi + diff --git a/configure.in b/configure.in index 8cf8cf5e9..15982033c 100644 --- a/configure.in +++ b/configure.in @@ -3,19 +3,26 @@ AC_PREREQ(2.59) -AC_INIT(GPSBabel, 1.3.4, BUG-REPORT-ADDRESS) - +AC_INIT(GPSBabel, 1.3.5, BUG-REPORT-ADDRESS) +# Increase GBBUILD for a new release +GBBUILD=16 # YYYYMMDD, please, if beta, i.e. "-beta20060413" -# PACKAGE_RELEASE="-beta20070711" +# PACKAGE_RELEASE="-beta20080305" AC_DEFINE_UNQUOTED(PACKAGE_RELEASE, "$PACKAGE_RELEASE", [Define to the release name of this package.]) AC_SUBST(PACKAGE_RELEASE) +DOCVERSION=`echo $PACKAGE_VERSION` +DOCVERSION=development +DOCVERSION=1.3.5 +AC_SUBST(DOCVERSION) + GBMAJOR=`echo $PACKAGE_VERSION | (IFS="."; read major minor micro; echo $major)` GBMINOR=`echo $PACKAGE_VERSION | (IFS="."; read major minor micro; echo $minor)` GBMICRO=`echo $PACKAGE_VERSION | (IFS="."; read major minor micro; echo $micro)` AC_SUBST(GBMAJOR) AC_SUBST(GBMINOR) AC_SUBST(GBMICRO) +AC_SUBST(GBBUILD) # AC_CONFIG_SRCDIR([nmea.c]) AC_CONFIG_HEADER([config.h]) @@ -84,6 +91,20 @@ AC_ARG_ENABLE(csv, AC_MSG_RESULT(no) fi +AC_MSG_CHECKING(whether to support maximum number of formats) +AC_ARG_ENABLE(most, + [ --enable-most=[(yes)|no]], + [ enable_most="$enableval"],[enable_most="yes"]) + if test "$enable_most" != "no" ; then + AC_MSG_RESULT(yes) + AC_DEFINE(MAXIMAL_ENABLED, 1, [1 to enable as many formats as possible]) + FMTS='$(ALL_FMTS)' + else + AC_MSG_RESULT(no) + FMTS='$(MINIMAL_FMTS)' + fi + AC_SUBST(FMTS) + AC_MSG_CHECKING(whether to support filters) AC_ARG_ENABLE(filters, [ --enable-filters=[(yes)|no]], @@ -166,9 +187,15 @@ case "$target" in USB_LIBS="`libusb-config --prefix`/lib/libusb.a -framework IOKit -framework CoreFoundation" LDFLAGS=$OLDFLAGS CDFLAGS=$OCDFLAGS + OSJEEPS=jeeps/gpslibusb.o + else + OSJEEPS=jeeps/gpsusbstub.o fi + ;; + *) + OSJEEPS=jeeps/gpslibusb.o + ;; esac - OSJEEPS=jeeps/gpslibusb.o CFLAGS="$OCFLAGS" # LIBS="$LIBS `libusb-config --libs`" else @@ -191,7 +218,9 @@ AC_ARG_WITH(expathdr, [ --with-expathdr[=DIR] Use this to specify the location of expat.h], [ xpathdr="$withval" ], [ case "$target" in - *-*-darwin*) + *-*-darwin6*|*-*-darwin7*|*-*-darwin8*) + # Restrict test to OS/X 10.4 and earlier. Leopard (10.5) + # provides expat and in a sensible location. if test -f /sw/include/expat.h ; then xpathdr=/sw/include/ fi @@ -213,16 +242,42 @@ fi AC_MSG_CHECKING(for libexpat) AC_ARG_WITH(libexpat, [ --with-libexpat[=DIR] Use this to specify expat library .], - [ CFLAGS="$CFLAGS -L$withval" - EXPAT_LIB="-L$withval -lexpat" + [ + # If the developer specified a reference + # to a FILE and not a directory, assume they are a highly + # trained professional that has specified a .a to to be used. + if test -f $withval ; then + EXPAT_LIB=$withval + else + CFLAGS="$CFLAGS -L$withval" + EXPAT_LIB="-L$withval -lexpat" + fi ], [ case "$target" in - *-*-darwin*) + *-*-darwin6*|*-*-darwin7*|*-*-darwin8*) + # Restrict test to OS/X 10.4 and earlier. Leopard (10.5) + # provides expat and in a sensible location. if test -f /sw/lib/libexpat.a ; then + # libexpat installed via fink EXPAT_LIB=/sw/lib/libexpat.a + LIBS="$LIBS -L/sw/lib" AC_DEFINE(HAVE_LIBEXPAT, 1, [Defined if you have libexpat]) AC_SUBST(EXPAT_LIB) fi + if test -f /opt/local/lib/libexpat.a ; then + # libexpat installed via macports + EXPAT_LIB=/opt/local/lib/libexpat.a + LIBS="$LIBS -L/opt/local/lib" + AC_DEFINE(HAVE_LIBEXPAT, 1, [Defined if you have libexpat]) + AC_SUBST(EXPAT_LIB) + fi + if test -f /usr/local/lib/libexpat.a ; then + # libexpat installed from source + EXPAT_LIB=/usr/local/lib/libexpat.a + LIBS="$LIBS -L/usr/local/lib" + AC_DEFINE(HAVE_LIBEXPAT, 1, [Defined if you have libexpat]) + AC_SUBST(EXPAT_LIB) + fi ;; *-*-freebsd*) if test -f /usr/local/lib/libexpat.a ; then @@ -288,5 +343,53 @@ AC_SUBST(DOCDIR) # AC_CHECK_FUNCS([atexit floor localtime_r memmove memset pow select sqrt strchr strcspn strdup strerror strncasecmp strrchr strspn strstr strtol strtoul]) AC_CHECK_FUNCS([nanosleep sleep]) +# +# Checks for how the system handles va_list +# paul.bromiley@man.ac.uk +# +dnl **** Check for va_copy **** +AC_CACHE_CHECK([for va_copy], ac_cv_c_va_copy, + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[va_list ap1, ap2; + va_copy(ap1,ap2); + ]])],[ac_cv_c_va_copy="yes"],[ac_cv_c_va_copy="no"]) + ) +if test "$ac_cv_c_va_copy" = "yes" +then + AC_DEFINE(HAVE_VA_COPY, 1, [Define if we have va_copy]) +fi +AC_CACHE_CHECK([for __va_copy], ac_cv_c___va_copy, + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[va_list ap1, ap2; + __va_copy(ap1,ap2); + ]])],[ac_cv_c___va_copy="yes"],[ac_cv_c___va_copy="no"]) + ) +if test "$ac_cv_c___va_copy" = "yes" +then + AC_DEFINE(HAVE___VA_COPY, 1, [Define if we have __va_copy]) +fi + +# +# Does this platform require array notation to assign to a va_list? +# +AC_MSG_CHECKING(va_list assignments need array notation) +AC_CACHE_VAL(ac_cv_valistisarray, + [AC_RUN_IFELSE([AC_LANG_SOURCE([[#include + #include + void foo(int i, ...) { + va_list ap1, ap2; + va_start(ap1, i); + ap2 = ap1; + if (va_arg(ap2, int) != 123 || va_arg(ap1, int) != 123) { exit(1); } + va_end(ap1); va_end(ap2); + } + int main() + { foo(0, 123); return(0); }]])],[ac_cv_valistisarray=false],[ac_cv_valistisarray=true],[ac_cv_valistisarray=false])]) + +if test "$ac_cv_valistisarray" = true ; then + AC_DEFINE(HAVE_VA_LIST_AS_ARRAY, 1, [Define as 1 if your va_list type is an array]) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi AC_CONFIG_FILES([Makefile gbversion.h xmldoc/makedoc tools/mkcapabilities win32/gpsbabel.rc jeeps/Makefile shapelib/Makefile zlib/empty]) AC_OUTPUT + diff --git a/csv_util.c b/csv_util.c index 81b833b76..31886f4b4 100644 --- a/csv_util.c +++ b/csv_util.c @@ -2,7 +2,7 @@ Utilities for parsing Character Separated Value files (CSV) Copyright (C) 2002 Alex Mottram (geo_alexm at cox-internet.com) - Copyright (C) 2002-2005 Robert Lipe + Copyright (C) 2002-2007 Robert Lipe This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,6 +28,7 @@ #include "strptime.h" #include "jeeps/gpsmath.h" #include "xmlgeneric.h" // for xml_fill_in_time. +#include "garmin_fs.h" #define MYNAME "CSV_UTIL" @@ -43,6 +44,88 @@ #define GPS_DATUM_WGS84 118 + +/* + * Internal numeric value to associate with each keyword in a style file. + * To add new keywords, just add an entry here, handle it in the switch + * statements below, add it to xcsv_tokens.in, and rebuild on a system + * that has GNU gperf on it. + */ +typedef enum { + XT_unused = 0, + XT_ALT_FEET, + XT_ALT_METERS, + XT_ANYNAME, + XT_CADENCE, + XT_CITY, + XT_CONSTANT, + XT_COUNTRY, + XT_DESCRIPTION, + XT_EXCEL_TIME, + XT_FACILITY, + XT_GEOCACHE_CONTAINER, + XT_GEOCACHE_DIFF, + XT_GEOCACHE_HINT, + XT_GEOCACHE_LAST_FOUND, + XT_GEOCACHE_PLACER, + XT_GEOCACHE_TERR, + XT_GEOCACHE_TYPE, + XT_GEOCACHE_ISAVAILABLE, + XT_GEOCACHE_ISARCHIVED, + XT_GMT_TIME, + XT_GPS_FIX, + XT_GPS_HDOP, + XT_GPS_PDOP, + XT_GPS_SAT, + XT_GPS_VDOP, + XT_HEART_RATE, + XT_HMSG_TIME, + XT_HMSL_TIME, + XT_ICON_DESCR, + XT_IGNORE, + XT_INDEX, + XT_ISO_TIME, + XT_ISO_TIME_MS, + XT_LATLON_HUMAN_READABLE, + XT_LAT_DECIMAL, + XT_LAT_DECIMALDIR, + XT_LAT_DIR, + XT_LAT_DIRDECIMAL, + XT_LAT_HUMAN_READABLE, + XT_LAT_INT32DEG, + XT_LAT_NMEA, + XT_LOCAL_TIME, + XT_LON_DECIMAL, + XT_LON_DECIMALDIR, + XT_LON_DIR, + XT_LON_DIRDECIMAL, + XT_LON_HUMAN_READABLE, + XT_LON_INT32DEG, + XT_LON_NMEA, + XT_MAP_EN_BNG, + XT_NOTES, + XT_PATH_COURSE, + XT_PATH_DISTANCE_KM, + XT_PATH_DISTANCE_MILES, + XT_PATH_SPEED, + XT_PATH_SPEED_KNOTS, + XT_PATH_SPEED_KPH, + XT_PATH_SPEED_MPH, + XT_PHONE_NR, + XT_POSTAL_CODE, + XT_ROUTE_NAME, + XT_SHORTNAME, + XT_STATE, + XT_STREET_ADDR, + XT_TIMET_TIME, + XT_TRACK_NAME, + XT_URL, + XT_URL_LINK_TEXT, + XT_YYYYMMDD_TIME +} xcsv_token; + +#include "xcsv_tokens.gperf" + /****************************************************************************/ /* obligatory global struct */ /****************************************************************************/ @@ -473,12 +556,14 @@ human_to_dec( const char *instr, double *outlat, double *outlon, int which ) if ( lat[0] != 999 ) *outlat = lat[0]; if ( lat[1] != 999 ) *outlat += lat[1]/60.0; if ( lat[2] != 999 ) *outlat += lat[2]/3600.0; + if ( *outlat > 360) *outlat = ddmm2degrees(*outlat); /* NMEA style */ if ( latsign ) *outlat *= latsign; } if ( outlon ) { if ( lon[0] != 999 ) *outlon = lon[0]; if ( lon[1] != 999 ) *outlon += lon[1]/60.0; if ( lon[2] != 999 ) *outlon += lon[2]/3600.0; + if ( *outlon > 360) *outlon = ddmm2degrees(*outlon); /* NMEA style */ if ( lonsign ) *outlon *= lonsign; } if (buff != instr) { @@ -599,8 +684,10 @@ void xcsv_ifield_add(char *key, char *val, char *pfc) { field_map_t *fmp = xcalloc(sizeof(*fmp), 1); + struct xt_mapping *xm = in_word_set(key, strlen(key)); fmp->key = key; + fmp->hashed_key = xm ? xm->xt_token : -1; fmp->val = val; fmp->printfc = pfc; @@ -616,8 +703,10 @@ void xcsv_ofield_add(char *key, char *val, char *pfc, int options) { field_map_t *fmp = xcalloc(sizeof(*fmp), 1); + struct xt_mapping *xm = in_word_set(key, strlen(key)); fmp->key = key; + fmp->hashed_key = xm ? xm->xt_token : -1; fmp->val = val; fmp->printfc = pfc; fmp->options = options; @@ -696,9 +785,14 @@ sscanftime( const char *s, const char *format, const int gmt ) else return mktime(&stm); } - + // Don't fuss for empty strings. + if (*s) { + warning("date parse of string '%s' with format '%s' failed.\n", + s, format); + } return 0; } + static time_t addhms( const char *s, const char *format ) @@ -762,13 +856,16 @@ static int writehms(char * buff, size_t bufsize, const char * format, time_t t, int gmt ) { - static struct tm * stmp; + static struct tm no_time = {0}; + static struct tm * stmp = &no_time; if (gmt) stmp = gmtime(&t); else stmp = localtime(&t); + if (stmp == NULL) stmp = &no_time; + return snprintf(buff, bufsize, format, stmp->tm_hour, stmp->tm_min, stmp->tm_sec, (stmp->tm_hour>=12?"PM":"AM") ); @@ -788,6 +885,17 @@ time_to_yyyymmdd(time_t t) return b; } +static garmin_fs_t * +gmsd_init(waypoint *wpt) +{ + garmin_fs_t *gmsd = GMSD_FIND(wpt); + if (gmsd == NULL) { + gmsd = garmin_fs_alloc(-1); + fs_chain_add(&wpt->fs, (format_specific_data *) gmsd); + } + return gmsd; +} + /*****************************************************************************/ /* xcsv_parse_val() - parse incoming data into the waypt structure. */ /* usage: xcsv_parse_val("-123.34", *waypt, *field_map) */ @@ -796,203 +904,217 @@ static void xcsv_parse_val(const char *s, waypoint *wpt, const field_map_t *fmp) { char *enclosure = ""; + if (0 == strcmp(fmp->printfc, "\"%s\"")) { enclosure = "\""; } - if (strcmp(fmp->key, "IGNORE") == 0) { - /* IGNORE -- Categorically ignore this... */ - } else - if (strcmp(fmp->key, "CONSTANT") == 0) { - /* CONSTANT -- Ignore on Input... */ - } else - if (strcmp(fmp->key, "ANYNAME") == 0) { - /* ANYNAME -- Ignore -- this is output magic. */ - } else - if (strcmp(fmp->key, "INDEX") == 0) { - /* IGNORE -- Calculated Sequence # For Ouput*/ - } else - if (strcmp(fmp->key, "SHORTNAME") == 0) { - wpt->shortname = csv_stringtrim(s, enclosure, 0); - } else - if (strcmp(fmp->key, "DESCRIPTION") == 0) { - wpt->description = csv_stringtrim(s, enclosure, 0); - } else - if (strcmp(fmp->key, "NOTES") == 0) { - wpt->notes = csv_stringtrim(s, "", 0); - } else - if (strcmp(fmp->key, "URL") == 0) { - wpt->url = csv_stringtrim(s, "", 0); - } else - if (strcmp(fmp->key, "URL_LINK_TEXT") == 0) { - wpt->url_link_text = csv_stringtrim(s, "", 0); - } else - if (strcmp(fmp->key, "ICON_DESCR") == 0) { - wpt->icon_descr = csv_stringtrim(s, "", 0); - wpt->wpt_flags.icon_descr_is_dynamic = 1; - } else + switch(fmp->hashed_key) { + case XT_IGNORE: + /* IGNORE -- Categorically ignore this... */ + break; + case XT_CONSTANT: + /* CONSTANT -- Ignore on Input... */ + break; + case XT_ANYNAME: + /* ANYNAME -- Ignore -- this is output magic. */ + break; + case XT_INDEX: + /* IGNORE -- Calculated Sequence # For Ouput*/ + break; + case XT_SHORTNAME: + wpt->shortname = csv_stringtrim(s, enclosure, 0); + break; + case XT_DESCRIPTION: + wpt->description = csv_stringtrim(s, enclosure, 0); + break; + case XT_NOTES: + wpt->notes = csv_stringtrim(s, "", 0); + break; + case XT_URL: + wpt->url = csv_stringtrim(s, "", 0); + break; + case XT_URL_LINK_TEXT: + wpt->url_link_text = csv_stringtrim(s, "", 0); + break; + case XT_ICON_DESCR: + wpt->icon_descr = csv_stringtrim(s, "", 0); + wpt->wpt_flags.icon_descr_is_dynamic = 1; + break; /* LATITUDE CONVERSIONS**************************************************/ - if (strcmp(fmp->key, "LAT_DECIMAL") == 0) { + case XT_LAT_DECIMAL: /* latitude as a pure decimal value */ - wpt->latitude = atof(s); - } else - if ((strcmp(fmp->key, "LAT_DECIMALDIR") == 0) || - (strcmp(fmp->key, "LAT_DIRDECIMAL") == 0)) { - /* latitude as a decimal with N/S in it. */ - wpt->latitude = decdir_to_dec(s); - } else - if (strcmp(fmp->key, "LAT_INT32DEG") == 0) { - /* latitude as a 32 bit integer offset */ - wpt->latitude = intdeg_to_dec((int) atof(s)); - } else - if ( strcmp(fmp->key, "LAT_HUMAN_READABLE") == 0) { - human_to_dec( s, &wpt->latitude, &wpt->longitude, 1 ); - } else - if ( strcmp(fmp->key, "LAT_NMEA") == 0) { + wpt->latitude = atof(s); + break; + case XT_LAT_DECIMALDIR: + case XT_LAT_DIRDECIMAL: + /* latitude as a decimal with N/S in it. */ + wpt->latitude = decdir_to_dec(s); + break; + case XT_LAT_INT32DEG: + /* latitude as a 32 bit integer offset */ + wpt->latitude = intdeg_to_dec((int) atof(s)); + break; + case XT_LAT_HUMAN_READABLE: + human_to_dec( s, &wpt->latitude, &wpt->longitude, 1 ); + break; + case XT_LAT_NMEA: wpt->latitude = ddmm2degrees(atof(s)); - } else - if ( strncmp(fmp->key, "LAT_10E", 7) == 0) { - wpt->latitude = atof(s) / pow((double)10, atof(fmp->key+7)); - } else + break; + // XT_LAT_10E is handled outside the switch. /* LONGITUDE CONVERSIONS ***********************************************/ - if (strcmp(fmp->key, "LON_DECIMAL") == 0) { + case XT_LON_DECIMAL: /* longitude as a pure decimal value */ - wpt->longitude = atof(s); - } else - if ((strcmp(fmp->key, "LON_DECIMALDIR") == 0) || - (strcmp(fmp->key, "LON_DIRDECIMAL") == 0)) { + wpt->longitude = atof(s); + break; + case XT_LON_DECIMALDIR: + case XT_LON_DIRDECIMAL: /* longitude as a decimal with N/S in it. */ - wpt->longitude = decdir_to_dec(s); - } else - if (strcmp(fmp->key, "LON_INT32DEG") == 0) { + wpt->longitude = decdir_to_dec(s); + break; + case XT_LON_INT32DEG: /* longitude as a 32 bit integer offset */ - wpt->longitude = intdeg_to_dec((int) atof(s)); - } else - if ( strcmp(fmp->key, "LON_HUMAN_READABLE") == 0) { - human_to_dec( s, &wpt->latitude, &wpt->longitude, 2 ); - } else - if ( strcmp(fmp->key, "LON_NMEA") == 0) { + wpt->longitude = intdeg_to_dec((int) atof(s)); + break; + case XT_LON_HUMAN_READABLE: + human_to_dec( s, &wpt->latitude, &wpt->longitude, 2 ); + break; + case XT_LON_NMEA: wpt->longitude = ddmm2degrees(atof(s)); - } else - if ( strncmp(fmp->key, "LON_10E", 7) == 0) { - wpt->longitude = atof(s) / pow((double)10, atof(fmp->key+7)); - } else + break; + // case XT_LON_10E is handled outside the switch. /* LAT AND LON CONVERSIONS ********************************************/ - if ( strcmp(fmp->key, "LATLON_HUMAN_READABLE") == 0) { - human_to_dec( s, &wpt->latitude, &wpt->longitude, 0 ); - } else + case XT_LATLON_HUMAN_READABLE: + human_to_dec( s, &wpt->latitude, &wpt->longitude, 0 ); + break; /* DIRECTIONS **********************************************************/ - if (strcmp(fmp->key, "LAT_DIR") == 0) { - /* latitude N/S. Ignore on input for now */ - } else - if (strcmp(fmp->key, "LON_DIR") == 0) { - /* longitude E/W. Ingore on input for now */ - } else + case XT_LAT_DIR: + /* latitude N/S. Ignore on input for now */ + break; + case XT_LON_DIR: + /* longitude E/W. Ingore on input for now */ + break; /* SPECIAL COORDINATES/GRID */ - if (strcmp(fmp->key, "MAP_EN_BNG") == 0) { - parse_coordinates(s, DATUM_OSGB36, grid_bng, - &wpt->latitude, &wpt->longitude, MYNAME); - } else + case XT_MAP_EN_BNG: + parse_coordinates(s, DATUM_OSGB36, grid_bng, + &wpt->latitude, &wpt->longitude, MYNAME); + break; /* ALTITUDE CONVERSIONS ************************************************/ - if (strcmp(fmp->key, "ALT_FEET") == 0) { - /* altitude in feet as a decimal value */ - wpt->altitude = FEET_TO_METERS(atof(s)); - if (wpt->altitude < unknown_alt + 1) - wpt->altitude = unknown_alt; - } else - if (strcmp(fmp->key, "ALT_METERS") == 0) { - /* altitude in meters as a decimal value */ - wpt->altitude = atof(s); - if (wpt->altitude < unknown_alt + 1) - wpt->altitude = unknown_alt; - } else + case XT_ALT_FEET: + /* altitude in feet as a decimal value */ + wpt->altitude = FEET_TO_METERS(atof(s)); + if (wpt->altitude < unknown_alt + 1) + wpt->altitude = unknown_alt; + break; + case XT_ALT_METERS: + /* altitude in meters as a decimal value */ + wpt->altitude = atof(s); + if (wpt->altitude < unknown_alt + 1) + wpt->altitude = unknown_alt; + break; /* PATH CONVERSIONS ************************************************/ - if (strcmp(fmp->key, "PATH_SPEED") == 0) { + case XT_PATH_SPEED: WAYPT_SET(wpt, speed, atof(s)); - } else - if (strcmp(fmp->key, "PATH_SPEED_KPH") == 0) { + break; + case XT_PATH_SPEED_KPH: WAYPT_SET(wpt, speed, KPH_TO_MPS(atof(s))); - } else - if (strcmp(fmp->key, "PATH_SPEED_MPH") == 0) { + break; + case XT_PATH_SPEED_MPH: WAYPT_SET(wpt, speed, MPH_TO_MPS(atof(s))); - } else - if (strcmp(fmp->key, "PATH_SPEED_KNOTS") == 0) { + break; + case XT_PATH_SPEED_KNOTS: WAYPT_SET(wpt, speed, KNOTS_TO_MPS(atof(s))); - } else - if (strcmp(fmp->key, "PATH_COURSE") == 0) { + break; + case XT_PATH_COURSE: WAYPT_SET(wpt, course, atof(s)); - } else + break; /* TIME CONVERSIONS ***************************************************/ - if (strcmp(fmp->key, "EXCEL_TIME") == 0) { + case XT_EXCEL_TIME: /* Time as Excel Time */ - wpt->creation_time = EXCEL_TO_TIMET(atof(s)); - } else - if (strcmp(fmp->key, "TIMET_TIME") == 0) { + wpt->creation_time = EXCEL_TO_TIMET(atof(s)); + break; + case XT_TIMET_TIME: /* Time as time_t */ - wpt->creation_time = atol(s); - } else - if (strcmp(fmp->key, "YYYYMMDD_TIME") == 0) { + wpt->creation_time = atol(s); + break; + case XT_YYYYMMDD_TIME: wpt->creation_time = yyyymmdd_to_time(s); - } else - if (strcmp(fmp->key, "GMT_TIME") == 0) { - wpt->creation_time = sscanftime(s, fmp->printfc, 1); - } else - if (strcmp(fmp->key, "LOCAL_TIME") == 0) { - wpt->creation_time = sscanftime(s, fmp->printfc, 0); - } else + break; + case XT_GMT_TIME: + wpt->creation_time += sscanftime(s, fmp->printfc, 1); + break; + case XT_LOCAL_TIME: + wpt->creation_time += sscanftime(s, fmp->printfc, 0); + break; /* Useful when time and date are in separate fields GMT / Local offset is handled by the two cases above */ - if ((strcmp(fmp->key, "HMSG_TIME") == 0)|| - (strcmp(fmp->key, "HMSL_TIME") == 0) ) { + case XT_HMSG_TIME: + case XT_HMSL_TIME: wpt->creation_time += addhms(s, fmp->printfc); - } else - if ((strcmp(fmp->key, "ISO_TIME") == 0) || - (strcmp(fmp->key, "ISO_TIME_MS") == 0)) { + break; + case XT_ISO_TIME: + case XT_ISO_TIME_MS: wpt->creation_time = xml_parse_time(s, &wpt->microseconds); - } else - if (strcmp(fmp->key, "GEOCACHE_LAST_FOUND") == 0) { + break; + case XT_GEOCACHE_LAST_FOUND: wpt->gc_data.last_found = yyyymmdd_to_time(s); - } else + break; /* GEOCACHING STUFF ***************************************************/ - if (strcmp(fmp->key, "GEOCACHE_DIFF") == 0) { + case XT_GEOCACHE_DIFF: /* Geocache Difficulty as an int */ - wpt->gc_data.diff = atof(s) * 10; - } else - if (strcmp(fmp->key, "GEOCACHE_TERR") == 0) { + wpt->gc_data.diff = atof(s) * 10; + break; + case XT_GEOCACHE_TERR: /* Geocache Terrain as an int */ - wpt->gc_data.terr = atof(s) * 10; - } else - if (strcmp(fmp->key, "GEOCACHE_TYPE") == 0) { + wpt->gc_data.terr = atof(s) * 10; + break; + case XT_GEOCACHE_TYPE: /* Geocache Type */ - wpt->gc_data.type = gs_mktype(s); - } else - if (strcmp(fmp->key, "GEOCACHE_CONTAINER") == 0) { - wpt->gc_data.container = gs_mkcont(s); - } else - if (strcmp(fmp->key, "GEOCACHE_HINT") == 0) { - wpt->gc_data.hint = csv_stringtrim(s, "", 0); - } else - if (strcmp(fmp->key, "GEOCACHE_PLACER") == 0) { - wpt->gc_data.placer = csv_stringtrim(s, "", 0); - } else - + wpt->gc_data.type = gs_mktype(s); + break; + case XT_GEOCACHE_CONTAINER: + wpt->gc_data.container = gs_mkcont(s); + break; + case XT_GEOCACHE_HINT: + wpt->gc_data.hint = csv_stringtrim(s, "", 0); + break; + case XT_GEOCACHE_PLACER: + wpt->gc_data.placer = csv_stringtrim(s, "", 0); + break; + case XT_GEOCACHE_ISAVAILABLE: + if ( case_ignore_strcmp(csv_stringtrim(s, "", 0), "False") == 0 ) + wpt->gc_data.is_available = status_false; + else if ( case_ignore_strcmp(csv_stringtrim(s, "", 0), "True") == 0 ) + wpt->gc_data.is_available = status_true; + else + wpt->gc_data.is_available = status_unknown; + break; + case XT_GEOCACHE_ISARCHIVED: + if ( case_ignore_strcmp(csv_stringtrim(s, "", 0), "False") == 0 ) + wpt->gc_data.is_archived = status_false; + else if ( case_ignore_strcmp(csv_stringtrim(s, "", 0), "True") == 0 ) + wpt->gc_data.is_archived = status_true; + else + wpt->gc_data.is_archived = status_unknown; + break; + /* GPS STUFF *******************************************************/ - if (strcmp(fmp->key, "GPS_HDOP") == 0) { - wpt->hdop = atof(s); - } else - if (strcmp(fmp->key, "GPS_VDOP") == 0) { + case XT_GPS_HDOP: + wpt->hdop = atof(s); + break; + case XT_GPS_VDOP: wpt->vdop = atof(s); - } else - if (strcmp(fmp->key, "GPS_PDOP") == 0) { + break; + case XT_GPS_PDOP: wpt->pdop = atof(s); - } else - if (strcmp(fmp->key, "GPS_SAT") == 0) { + break; + case XT_GPS_SAT: wpt->sat = atoi(s); - } else - if (strcmp(fmp->key, "GPS_FIX") == 0) { + break; + case XT_GPS_FIX: wpt->fix = atoi(s)-1; if ( wpt->fix < fix_2d) { if (!case_ignore_strcmp(s, "none")) @@ -1004,29 +1126,78 @@ xcsv_parse_val(const char *s, waypoint *wpt, const field_map_t *fmp) else wpt->fix = fix_unknown; } - } else + break; /* Tracks and routes *********************************************/ - if ( strcmp ( fmp->key, "ROUTE_NAME") == 0) { + case XT_ROUTE_NAME: if (csv_route) csv_route->rte_name = csv_stringtrim(s, enclosure, 0); - } else - if ( strcmp ( fmp->key, "TRACK_NAME") == 0) { + break; + case XT_TRACK_NAME: if (csv_track) csv_track->rte_name = csv_stringtrim(s, enclosure, 0); - } else + break; /* OTHER STUFF ***************************************************/ - if ( strcmp( fmp->key, "PATH_DISTANCE_MILES") == 0) { - /* Ignored on input */ - } else - if ( strcmp( fmp->key, "HEART_RATE") == 0) { - wpt->heartrate = atoi(s); - } else - if ( strcmp( fmp->key, "CADENCE") == 0) { - wpt->cadence = atoi(s); - } else - if ( strcmp( fmp->key, "PATH_DISTANCE_KM") == 0 ) { - /* Ignored on input */ - } else { - warning( MYNAME ": Unknown style directive: %s\n", fmp->key); + case XT_PATH_DISTANCE_MILES: + /* Ignored on input */ + break; + case XT_HEART_RATE: + wpt->heartrate = atoi(s); + break; + case XT_CADENCE: + wpt->cadence = atoi(s); + break; + case XT_PATH_DISTANCE_KM: + /* Ignored on input */ + break; + /* GMSD ****************************************************************/ + case XT_COUNTRY: { + garmin_fs_t *gmsd = gmsd_init(wpt); + GMSD_SET(country, csv_stringtrim(s, enclosure, 0)); + } + break; + case XT_STATE: { + garmin_fs_t *gmsd = gmsd_init(wpt); + GMSD_SET(state, csv_stringtrim(s, enclosure, 0)); + } + break; + case XT_CITY: { + garmin_fs_t *gmsd = gmsd_init(wpt); + GMSD_SET(city, csv_stringtrim(s, enclosure, 0)); + } + break; + case XT_STREET_ADDR: { + garmin_fs_t *gmsd = gmsd_init(wpt); + GMSD_SET(addr, csv_stringtrim(s, enclosure, 0)); + } + break; + case XT_POSTAL_CODE: { + garmin_fs_t *gmsd = gmsd_init(wpt); + GMSD_SET(postal_code, csv_stringtrim(s, enclosure, 0)); + } + break; + case XT_PHONE_NR: { + garmin_fs_t *gmsd = gmsd_init(wpt); + GMSD_SET(phone_nr, csv_stringtrim(s, enclosure, 0)); + } + break; + case XT_FACILITY: { + garmin_fs_t *gmsd = gmsd_init(wpt); + GMSD_SET(facility, csv_stringtrim(s, enclosure, 0)); + } + break; + case -1: + if (strncmp(fmp->key, "LON_10E", 7) == 0) { + wpt->longitude = atof(s) / pow((double)10, atof(fmp->key+7)); + } else + if (strncmp(fmp->key, "LAT_10E", 7) == 0) { + wpt->latitude = atof(s) / pow((double)10, atof(fmp->key+7)); + } else { + warning( MYNAME ": Unknown style directive: %s\n", fmp->key); + } + break; + + default: + fatal("This can't happen\n"); + break; } } @@ -1049,13 +1220,9 @@ xcsv_data_read(void) csv_route = csv_track = NULL; if (xcsv_file.datatype == trkdata) { - trk = route_head_alloc(); - track_add_head(trk); csv_track = trk; } else if (xcsv_file.datatype == rtedata) { - rte = route_head_alloc(); - route_add_head(rte); csv_route = rte; } @@ -1126,11 +1293,22 @@ xcsv_data_read(void) switch(xcsv_file.datatype) { case 0: case wptdata: - waypt_add(wpt_tmp); break; + waypt_add(wpt_tmp); + break; case trkdata: - track_add_wpt(trk, wpt_tmp); break; - case rtedata: - route_add_wpt(rte, wpt_tmp); break; + if (trk == NULL) { + trk = route_head_alloc(); + track_add_head(trk); + } + track_add_wpt(trk, wpt_tmp); + break; + case rtedata: + if (rte == NULL) { + rte = route_head_alloc(); + route_add_head(rte); + } + route_add_wpt(rte, wpt_tmp); + break; default: ; } } @@ -1252,26 +1430,28 @@ xcsv_waypt_pr(const waypoint *wpt) i++; #define writebuff(b, fmt, data) snprintf(b, sizeof(b), fmt, data) - if (strcmp(fmp->key, "IGNORE") == 0) { + switch(fmp->hashed_key) { + case XT_IGNORE: /* IGNORE -- Write the char printf conversion */ writebuff(buff, fmp->printfc, ""); - } else - if (strcmp(fmp->key, "INDEX") == 0) { + break; + case XT_INDEX: writebuff(buff, fmp->printfc, waypt_out_count + atoi(fmp->val)); - } else - if (strcmp(fmp->key, "CONSTANT") == 0) { + break; + case XT_CONSTANT: { const char *cp = xcsv_get_char_from_constant_table(fmp->val); if (cp) { writebuff(buff, fmp->printfc, cp); - } else { + } else { writebuff(buff, fmp->printfc, fmp->val); } - } else - if (strcmp(fmp->key, "SHORTNAME") == 0) { + } + break; + case XT_SHORTNAME: writebuff(buff, fmp->printfc, (shortname && *shortname) ? shortname : fmp->val); - } else - if (strcmp(fmp->key, "ANYNAME") == 0) { + break; + case XT_ANYNAME: if (wpt->shortname) { anyname = xstrdup(wpt->shortname); } else @@ -1290,16 +1470,16 @@ xcsv_waypt_pr(const waypoint *wpt) writebuff(buff, fmp->printfc, anyname); xfree(anyname); - } else - if (strcmp(fmp->key, "DESCRIPTION") == 0) { + break; + case XT_DESCRIPTION: writebuff(buff, fmp->printfc, (description && *description) ? description : fmp->val); - } else - if (strcmp(fmp->key, "NOTES") == 0) { + break; + case XT_NOTES: writebuff(buff, fmp->printfc, (wpt->notes && *wpt->notes) ? wpt->notes : fmp->val); - } else - if (strcmp(fmp->key, "URL") == 0) { + break; + case XT_URL: { int off = 0; if (xcsv_urlbase) { strcpy(buff, xcsv_urlbase); @@ -1309,243 +1489,255 @@ xcsv_waypt_pr(const waypoint *wpt) snprintf(buff + off, sizeof(buff) - off, fmp->printfc, wpt->url); else strcpy(buff, (fmp->val && *fmp->val) ? fmp->val : "\"\""); - } else - if (strcmp(fmp->key, "URL_LINK_TEXT") == 0) { + } + break; + case XT_URL_LINK_TEXT: snprintf(buff, sizeof(buff), fmp->printfc, (wpt->url_link_text && *wpt->url_link_text) ? wpt->url_link_text : fmp->val); - } else - if (strcmp(fmp->key, "ICON_DESCR") == 0) { + break; + case XT_ICON_DESCR: writebuff(buff, fmp->printfc, (wpt->icon_descr && *wpt->icon_descr) ? wpt->icon_descr : fmp->val); - } else + break; /* LATITUDE CONVERSION***********************************************/ - if (strcmp(fmp->key, "LAT_DECIMAL") == 0) { + case XT_LAT_DECIMAL: /* latitude as a pure decimal value */ writebuff(buff, fmp->printfc, lat); - } else - if (strcmp(fmp->key, "LAT_DECIMALDIR") == 0) { + break; + case XT_LAT_DECIMALDIR: /* latitude as a decimal value with N/S after it */ snprintf(buff, sizeof(buff), fmp->printfc, fabs(lat), LAT_DIR(lat)); - } else - if (strcmp(fmp->key, "LAT_DIRDECIMAL") == 0) { + break; + case XT_LAT_DIRDECIMAL: /* latitude as a decimal value with N/S before it */ snprintf(buff, sizeof(buff), fmp->printfc, LAT_DIR(lat), fabs(lat)); - } else - if (strcmp(fmp->key, "LAT_INT32DEG") == 0) { + break; + case XT_LAT_INT32DEG: /* latitude as an integer offset from 0 degrees */ writebuff(buff, fmp->printfc, dec_to_intdeg(lat)); - } else - if (strcmp(fmp->key, "LAT_HUMAN_READABLE") == 0) { + break; + case XT_LAT_HUMAN_READABLE: dec_to_human( buff, fmp->printfc, "SN", lat ); - } else - if (strcmp(fmp->key, "LAT_NMEA") == 0) { + break; + case XT_LAT_NMEA: writebuff(buff, fmp->printfc, degrees2ddmm(lat)); - } else - if (strncmp(fmp->key, "LAT_10E", 7) == 0) { - writebuff(buff, fmp->printfc, lat * pow((double)10, atof(fmp->key+7))); - } else - + break; + // case XT_LAT_10E is handled outside the switch. /* LONGITUDE CONVERSIONS*********************************************/ - if (strcmp(fmp->key, "LON_DECIMAL") == 0) { + case XT_LON_DECIMAL: /* longitude as a pure decimal value */ writebuff(buff, fmp->printfc, lon); - } else - if (strcmp(fmp->key, "LON_DECIMALDIR") == 0) { + break; + case XT_LON_DECIMALDIR: /* latitude as a decimal value with N/S after it */ snprintf(buff, sizeof(buff), fmp->printfc, fabs(lon), LON_DIR(lon)); - } else - if (strcmp(fmp->key, "LON_DIRDECIMAL") == 0) { + break; + case XT_LON_DIRDECIMAL: /* latitude as a decimal value with N/S before it */ snprintf(buff, sizeof(buff), fmp->printfc, LON_DIR(lon), fabs(lon)); - } else - if (strcmp(fmp->key, "LON_INT32DEG") == 0) { + break; + case XT_LON_INT32DEG: /* longitudee as an integer offset from 0 degrees */ writebuff(buff, fmp->printfc, dec_to_intdeg(lon)); - } else - if (strcmp(fmp->key, "LON_HUMAN_READABLE") == 0) { + break; + case XT_LON_HUMAN_READABLE: dec_to_human( buff, fmp->printfc, "WE", lon ); - } else - if (strcmp(fmp->key, "LATLON_HUMAN_READABLE") == 0) { + break; + case XT_LATLON_HUMAN_READABLE: dec_to_human( buff, fmp->printfc, "SN", lat ); if ( !isspace(buff[strlen(buff)])) strcat( buff, " " ); dec_to_human( buff+strlen(buff), fmp->printfc, "WE", lon ); - } else - if (strcmp(fmp->key, "LON_NMEA") == 0) { + break; + case XT_LON_NMEA: writebuff(buff, fmp->printfc, degrees2ddmm(lon)); - } else - if (strncmp(fmp->key, "LON_10E", 7) == 0) { - writebuff(buff, fmp->printfc, lon * pow((double)10, atof(fmp->key+7))); - } else - + break; + // case XT_LON_10E is handled outside the switch. /* DIRECTIONS *******************************************************/ - if (strcmp(fmp->key, "LAT_DIR") == 0) { + case XT_LAT_DIR: /* latitude N/S as a char */ writebuff(buff, fmp->printfc, LAT_DIR(lat)); - } else - if (strcmp(fmp->key, "LON_DIR") == 0) { + break; + case XT_LON_DIR: /* longitude E/W as a char */ writebuff(buff, fmp->printfc, LON_DIR(lon)); - } else + break; /* SPECIAL COORDINATES */ - if (strcmp(fmp->key, "MAP_EN_BNG") == 0) { + case XT_MAP_EN_BNG: { char map[3]; double north, east; if (! GPS_Math_WGS84_To_UKOSMap_M(wpt->latitude, wpt->longitude, &east, &north, map)) fatal(MYNAME ": Position (%.5f/%.5f) outside of BNG.\n", wpt->latitude, wpt->longitude); snprintf(buff, sizeof(buff), fmp->printfc, map, (int)(east + 0.5), (int)(north + 0.5)); - } else + } + break; /* ALTITUDE CONVERSIONS**********************************************/ - if (strcmp(fmp->key, "ALT_FEET") == 0) { + case XT_ALT_FEET: /* altitude in feet as a decimal value */ writebuff(buff, fmp->printfc, METERS_TO_FEET(wpt->altitude)); - } else - if (strcmp(fmp->key, "ALT_METERS") == 0) { + break; + case XT_ALT_METERS: /* altitude in meters as a decimal value */ writebuff(buff, fmp->printfc, wpt->altitude); - } else + break; /* DISTANCE CONVERSIONS**********************************************/ - if (strcmp(fmp->key, "PATH_DISTANCE_MILES") == 0) { + case XT_PATH_DISTANCE_MILES: /* path (route/track) distance in miles */ writebuff( buff, fmp->printfc, pathdist ); - } else - if (strcmp(fmp->key, "PATH_DISTANCE_KM") == 0) { + break; + case XT_PATH_DISTANCE_KM: /* path (route/track) distance in */ writebuff( buff, fmp->printfc, pathdist * 5280*12*2.54/100/1000 ); - } else - if (strcmp(fmp->key, "PATH_SPEED") == 0) { + break; + case XT_PATH_SPEED: writebuff( buff, fmp->printfc, wpt->speed ); - } else - if (strcmp(fmp->key, "PATH_SPEED_KPH") == 0) { + break; + case XT_PATH_SPEED_KPH: writebuff( buff, fmp->printfc, MPS_TO_KPH(wpt->speed)); - } else - if (strcmp(fmp->key, "PATH_SPEED_MPH") == 0) { + break; + case XT_PATH_SPEED_MPH: writebuff( buff, fmp->printfc, MPS_TO_MPH(wpt->speed)); - } else - if (strcmp(fmp->key, "PATH_SPEED_KNOTS") == 0) { + break; + case XT_PATH_SPEED_KNOTS: writebuff( buff, fmp->printfc, MPS_TO_KNOTS(wpt->speed)); - } else - if (strcmp(fmp->key, "PATH_COURSE") == 0) { + break; + case XT_PATH_COURSE: writebuff( buff, fmp->printfc, wpt->course ); - } else + break; /* HEART RATE CONVERSION***********************************************/ - if (strcmp(fmp->key, "HEART_RATE") == 0) { + case XT_HEART_RATE: writebuff(buff, fmp->printfc, wpt->heartrate); - } else + break; /* CADENCE CONVERSION***********************************************/ - if (strcmp(fmp->key, "CADENCE") == 0) { + case XT_CADENCE: writebuff(buff, fmp->printfc, wpt->cadence); - } else + break; /* TIME CONVERSIONS**************************************************/ - if (strcmp(fmp->key, "EXCEL_TIME") == 0) { + case XT_EXCEL_TIME: /* creation time as an excel (double) time */ writebuff(buff, fmp->printfc, TIMET_TO_EXCEL(wpt->creation_time)); - } else - if (strcmp(fmp->key, "TIMET_TIME") == 0) { + break; + case XT_TIMET_TIME: /* time as a time_t variable */ writebuff(buff, fmp->printfc, wpt->creation_time); - } else - if (strcmp(fmp->key, "YYYYMMDD_TIME") == 0) { + break; + case XT_YYYYMMDD_TIME: writebuff(buff, fmp->printfc, time_to_yyyymmdd(wpt->creation_time)); - } else - if (strcmp(fmp->key, "GMT_TIME") == 0) { + break; + case XT_GMT_TIME: writetime(buff, sizeof buff, fmp->printfc, wpt->creation_time, 1 ); - } else - if (strcmp(fmp->key, "LOCAL_TIME") == 0) { + break; + case XT_LOCAL_TIME: writetime(buff, sizeof buff, fmp->printfc, wpt->creation_time, 0 ); - } else - if (strcmp(fmp->key, "HMSG_TIME") == 0) { + break; + case XT_HMSG_TIME: writehms(buff, sizeof buff, fmp->printfc, wpt->creation_time, 1 ); - } else - if (strcmp(fmp->key, "HMSL_TIME") == 0) { + break; + case XT_HMSL_TIME: writehms(buff, sizeof buff, fmp->printfc, wpt->creation_time, 0 ); - } else - if (strcmp(fmp->key, "ISO_TIME") == 0) { + break; + case XT_ISO_TIME: writetime(buff, sizeof buff, "%Y-%m-%dT%H:%M:%SZ", wpt->creation_time, 1 ); - } else - if (strcmp(fmp->key, "ISO_TIME_MS") == 0) { + break; + case XT_ISO_TIME_MS: xml_fill_in_time(buff, wpt->creation_time, wpt->microseconds, XML_LONG_TIME); - } else - if (strcmp(fmp->key, "GEOCACHE_LAST_FOUND") == 0) { + break; + case XT_GEOCACHE_LAST_FOUND: writebuff(buff, fmp->printfc, time_to_yyyymmdd(wpt->gc_data.last_found)); - } else + break; /* GEOCACHE STUFF **************************************************/ - if (strcmp(fmp->key, "GEOCACHE_DIFF") == 0) { + case XT_GEOCACHE_DIFF: /* Geocache Difficulty as a double */ writebuff(buff, fmp->printfc, wpt->gc_data.diff / 10.0); field_is_unknown = !wpt->gc_data.diff; - } else - if (strcmp(fmp->key, "GEOCACHE_TERR") == 0) { + break; + case XT_GEOCACHE_TERR: /* Geocache Terrain as a double */ writebuff(buff, fmp->printfc, wpt->gc_data.terr / 10.0); field_is_unknown = !wpt->gc_data.terr; - } else - if (strcmp(fmp->key, "GEOCACHE_CONTAINER") == 0) { + break; + case XT_GEOCACHE_CONTAINER: /* Geocache Container */ writebuff(buff, fmp->printfc, gs_get_container(wpt->gc_data.container)); field_is_unknown = wpt->gc_data.container == gc_unknown; - } else - if (strcmp(fmp->key, "GEOCACHE_TYPE") == 0) { + break; + case XT_GEOCACHE_TYPE: /* Geocache Type */ writebuff(buff, fmp->printfc, gs_get_cachetype(wpt->gc_data.type)); field_is_unknown = wpt->gc_data.type == gt_unknown; - } else - if (strcmp(fmp->key, "GEOCACHE_HINT") == 0) { + break; + case XT_GEOCACHE_HINT: writebuff(buff, fmp->printfc, NONULL(wpt->gc_data.hint)); field_is_unknown = !wpt->gc_data.hint; - } else - if (strcmp(fmp->key, "GEOCACHE_PLACER") == 0) { + break; + case XT_GEOCACHE_PLACER: writebuff(buff, fmp->printfc, NONULL(wpt->gc_data.placer)); field_is_unknown = !wpt->gc_data.placer; - } else + break; + case XT_GEOCACHE_ISAVAILABLE: + if ( wpt->gc_data.is_available == status_false ) + writebuff(buff, fmp->printfc, "False"); + else if ( wpt->gc_data.is_available == status_true ) + writebuff(buff, fmp->printfc, "True"); + else + writebuff(buff, fmp->printfc, "Unknown"); + break; + case XT_GEOCACHE_ISARCHIVED: + if ( wpt->gc_data.is_archived == status_false ) + writebuff(buff, fmp->printfc, "False"); + else if ( wpt->gc_data.is_archived == status_true ) + writebuff(buff, fmp->printfc, "True"); + else + writebuff(buff, fmp->printfc, "Unknown"); + break; /* Tracks and Routes ***********************************************/ - if (strcmp(fmp->key, "TRACK_NAME") == 0) { + case XT_TRACK_NAME: if (csv_track) writebuff(buff, fmp->printfc, NONULL(csv_track->rte_name)); - } else - if (strcmp(fmp->key, "ROUTE_NAME") == 0) { + break; + case XT_ROUTE_NAME: if (csv_route) writebuff(buff, fmp->printfc, NONULL(csv_route->rte_name)); - } else + break; /* GPS STUFF *******************************************************/ - if (strcmp(fmp->key, "GPS_HDOP") == 0) { + case XT_GPS_HDOP: writebuff(buff, fmp->printfc, wpt->hdop); field_is_unknown = !wpt->hdop; - } else - if (strcmp(fmp->key, "GPS_VDOP") == 0) { + break; + case XT_GPS_VDOP: writebuff(buff, fmp->printfc, wpt->vdop); field_is_unknown = !wpt->vdop; - } else - if (strcmp(fmp->key, "GPS_PDOP") == 0) { + break; + case XT_GPS_PDOP: writebuff(buff, fmp->printfc, wpt->pdop); field_is_unknown = !wpt->pdop; - } else - if (strcmp(fmp->key, "GPS_SAT") == 0) { + break; + case XT_GPS_SAT: writebuff(buff, fmp->printfc, wpt->sat); field_is_unknown = !wpt->sat; - } else - if (strcmp(fmp->key, "GPS_FIX") == 0) { + break; + case XT_GPS_FIX: { char *fix = NULL; switch (wpt->fix) { case fix_unknown: @@ -1569,11 +1761,56 @@ xcsv_waypt_pr(const waypoint *wpt) break; } writebuff(buff, fmp->printfc, fix); - } else { - warning( MYNAME ": Unknown style directive: %s\n", fmp->key); - } - - + } + break; + /* GMSD ************************************************************/ + case XT_COUNTRY: { + garmin_fs_t *gmsd = GMSD_FIND(wpt); + writebuff(buff, fmp->printfc, GMSD_GET(country, "")); + } + break; + case XT_STATE: { + garmin_fs_t *gmsd = GMSD_FIND(wpt); + writebuff(buff, fmp->printfc, GMSD_GET(state, "")); + } + break; + case XT_CITY: { + garmin_fs_t *gmsd = GMSD_FIND(wpt); + writebuff(buff, fmp->printfc, GMSD_GET(city, "")); + } + break; + case XT_POSTAL_CODE: { + garmin_fs_t *gmsd = GMSD_FIND(wpt); + writebuff(buff, fmp->printfc, GMSD_GET(postal_code, "")); + } + break; + case XT_STREET_ADDR: { + garmin_fs_t *gmsd = GMSD_FIND(wpt); + writebuff(buff, fmp->printfc, GMSD_GET(addr, "")); + } + break; + case XT_PHONE_NR: { + garmin_fs_t *gmsd = GMSD_FIND(wpt); + writebuff(buff, fmp->printfc, GMSD_GET(phone_nr, "")); + } + break; + case XT_FACILITY: { + garmin_fs_t *gmsd = GMSD_FIND(wpt); + writebuff(buff, fmp->printfc, GMSD_GET(facility, "")); + } + break; + case -1: + if (strncmp(fmp->key, "LON_10E", 7) == 0) { + writebuff(buff, fmp->printfc, lon * pow((double)10, atof(fmp->key+7))); + } else + if (strncmp(fmp->key, "LAT_10E", 7) == 0) { + writebuff(buff, fmp->printfc, lat * pow((double)10, atof(fmp->key+7))); + } + break; + default: + warning( MYNAME ": Unknown style directive: %s\n", fmp->key); + break; + } obuff = csv_stringclean(buff, xcsv_file.badchars); if (field_is_unknown && fmp->options & OPTIONS_OPTIONAL) { @@ -1592,7 +1829,7 @@ xcsv_waypt_pr(const waypoint *wpt) next: xfree(obuff); - } + } gbfprintf (xcsv_file.xcsvfp, "%s", xcsv_file.record_delimiter); diff --git a/csv_util.h b/csv_util.h index e8659a82b..ab29e3771 100644 --- a/csv_util.h +++ b/csv_util.h @@ -81,6 +81,7 @@ typedef struct field_map { char * key; char * val; char * printfc; + int hashed_key; int options; } field_map_t; diff --git a/defs.h b/defs.h index eb109dd21..40b487eef 100644 --- a/defs.h +++ b/defs.h @@ -122,6 +122,18 @@ # define NORETURN void #endif +#ifndef HAVE_VA_COPY +# ifdef __va_copy +# define va_copy(DEST,SRC) __va_copy((DEST),(SRC)) +# else +# ifdef HAVE_VA_LIST_AS_ARRAY +# define va_copy(DEST,SRC) (*(DEST) = *(SRC)) +# else +# define va_copy(DEST,SRC) ((DEST) = (SRC)) +# endif +# endif +#endif + /* * Common definitions. There should be no protocol or file-specific * data in this file. @@ -138,6 +150,12 @@ typedef enum { fix_pps } fix_type; +typedef enum { + status_unknown=0, + status_true, + status_false +} status_type; + /* * Define globally on which kind of data gpsbabel is working. * Important for "file types" that are essentially a communication @@ -180,6 +198,7 @@ extern global_options global_opts; extern const char gpsbabel_version[]; extern time_t gpsbabel_now; /* gpsbabel startup-time; initialized in main.c with time() */ extern time_t gpsbabel_time; /* gpsbabel startup-time; initialized in main.c with current_time(), ! ZERO within testo ! */ +extern int geocaches_present; #define MILLI_TO_MICRO(t) (t * 1000) /* Milliseconds to Microseconds */ #define MICRO_TO_MILLI(t) (t / 1000) /* Microseconds to Milliseconds*/ @@ -233,13 +252,15 @@ typedef struct { geocache_container container:4; unsigned int diff:6; /* (multiplied by ten internally) */ unsigned int terr:6; /* (likewise) */ + status_type is_archived:2; + status_type is_available:2; time_t exported; time_t last_found; char *placer; /* Placer name */ int placer_id; /* Placer id */ char *hint; /* all these UTF8, XML entities removed, May be not HTML. */ utf_string desc_short; - utf_string desc_long; + utf_string desc_long; } geocache_data ; typedef struct xml_tag { @@ -302,6 +323,7 @@ typedef struct { unsigned int icon_descr_is_dynamic:1; unsigned int shortname_is_synthetic:1; unsigned int cet_converted:1; /* strings are converted to UTF8; interesting only for input */ + unsigned int fmt_use:1; /* lightweight "extra data" */ /* "flagged fields" */ unsigned int temperature:1; /* temperature field is set */ unsigned int proximity:1; /* proximity field is set */ @@ -316,7 +338,7 @@ typedef struct { } wp_flags; #define WAYPT_SET(wpt,member,val) { wpt->member = (val); wpt->wpt_flags.member = 1; } -#define WAYPT_GET(wpt,member,def) (wpt->wpt_flags.member) ? (wpt->member) : (def) +#define WAYPT_GET(wpt,member,def) ((wpt->wpt_flags.member) ? (wpt->member) : (def)) #define WAYPT_UNSET(wpt,member) wpt->wpt_flags.member = 0 #define WAYPT_HAS(wpt,member) (wpt->wpt_flags.member) /* @@ -698,6 +720,10 @@ void waypt_disp(const waypoint *); void waypt_status_disp(int total_ct, int myct); double waypt_time(const waypoint *wpt); double waypt_speed(const waypoint *A, const waypoint *B); +double waypt_speed_ex(const waypoint *A, const waypoint *B); +double waypt_course(const waypoint *A, const waypoint *B); +double waypt_distance(const waypoint *A, const waypoint *B); +double waypt_distance_ex(const waypoint *A, const waypoint *B); NORETURN fatal(const char *, ...) PRINTFLIKE(1, 2); void is_fatal(const int condition, const char *, ...) PRINTFLIKE(2, 3); @@ -773,6 +799,7 @@ char *xstrrstr(const char *s1, const char *s2); void rtrim(char *s); char * lrtrim(char *s); int xasprintf(char **strp, const char *fmt, ...); +int xvasprintf(char **strp, const char *fmt, va_list ap); char *strupper(char *src); char *strlower(char *src); signed int get_tz_offset(void); @@ -851,7 +878,9 @@ typedef struct { signed int be_read16(const void *p); signed int be_read32(const void *p); signed int le_read16(const void *p); +unsigned int le_readu16(const void *p); signed int le_read32(const void *p); +unsigned int le_readu32(const void *p); void le_read64(void *dest, const void *src); void be_write16(void *pp, const unsigned i); void be_write32(void *pp, const unsigned i); @@ -891,17 +920,23 @@ typedef enum { grid_lat_lon_dmm = 1, grid_lat_lon_dms = 2, grid_bng = 3, - grid_utm = 4 + grid_utm = 4, + grid_swiss = 5 } grid_type; #define GRID_INDEX_MIN grid_lat_lon_ddd -#define GRID_INDEX_MAX grid_utm +#define GRID_INDEX_MAX grid_swiss #define DATUM_OSGB36 86 #define DATUM_WGS84 118 +/* + * From parse.c + */ int parse_coordinates(const char *str, int datum, const grid_type grid, double *latitude, double *longitude, const char *module); +int parse_distance(const char *str, double *val, double scale, const char *module); +int parse_speed(const char *str, double *val, const double scale, const char *module); /* * From util_crc.c diff --git a/delgpl.c b/delgpl.c index 6f6e1fc2b..37dac7ac2 100644 --- a/delgpl.c +++ b/delgpl.c @@ -38,13 +38,13 @@ typedef struct gpl_point { unsigned int dummy3; } gpl_point_t; -static FILE *gplfile_in; -static FILE *gplfile_out; +static gbfile *gplfile_in; +static gbfile *gplfile_out; static void gpl_rd_init(const char *fname) { - gplfile_in = xfopen(fname, "rb", MYNAME); + gplfile_in = gbfopen_le(fname, "rb", MYNAME); if (sizeof(struct gpl_point) != 56) { fatal(MYNAME ": gpl_point is %lu instead of 56.\n", (unsigned long) sizeof(struct gpl_point)); @@ -62,7 +62,7 @@ gpl_read(void) track_head = route_head_alloc(); track_add_head(track_head); - while (fread(&gp, sizeof(gp), 1, gplfile_in) > 0) { + while (gbfread(&gp, sizeof(gp), 1, gplfile_in) > 0) { wpt_tmp = waypt_new(); wpt_tmp->latitude = le_read_double(&gp.lat); wpt_tmp->longitude = le_read_double(&gp.lon); @@ -84,19 +84,19 @@ gpl_read(void) static void gpl_rd_deinit(void) { - fclose(gplfile_in); + gbfclose(gplfile_in); } static void gpl_wr_init(const char *fname) { - gplfile_out = xfopen(fname, "wb", MYNAME); + gplfile_out = gbfopen_le(fname, "wb", MYNAME); } static void gpl_wr_deinit(void) { - fclose(gplfile_out); + gbfclose(gplfile_out); } static void @@ -117,7 +117,7 @@ gpl_trackpt(const waypoint *wpt) le_write_double(&gp.heading, heading ); le_write32(&gp.tm, wpt->creation_time); - fwrite(&gp, sizeof(gp), 1, gplfile_out); + gbfwrite(&gp, sizeof(gp), 1, gplfile_out); } static void diff --git a/destinator.c b/destinator.c new file mode 100644 index 000000000..59b3c323b --- /dev/null +++ b/destinator.c @@ -0,0 +1,588 @@ +/* + + Support for Destinator POI's, Itineraries and Tracklogs. + ( as described at "http://mozoft.com/d3log.html" ) + + Copyright (C) 2008 Olaf Klein, o.b.klein@gpsbabel.org + + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" +#include "cet.h" +#include "garmin_fs.h" +#include "strptime.h" +#include +#include + +#define MYNAME "destinator" +#define DST_DYN_POI "Dynamic POI" +#define DST_ITINERARY "City->Street" + +static +arglist_t destinator_args[] = { + ARG_TERMINATOR +}; + +static gbfile *fin, *fout; +static gpsdata_type data_type; + + +/*******************************************************************************/ +/* READER */ +/*-----------------------------------------------------------------------------*/ + +static garmin_fs_t * +gmsd_init(waypoint *wpt) +{ + garmin_fs_t *gmsd = GMSD_FIND(wpt); + if (gmsd == NULL) { + gmsd = garmin_fs_alloc(-1); + fs_chain_add(&wpt->fs, (format_specific_data *) gmsd); + } + return gmsd; +} + +static char * +read_wcstr(const int discard) +{ + short *buff = NULL, c; + int size = 0, pos = 0; + + while ((c = gbfgetint16(fin))) { + if (size == 0) { + size = 16; + buff = xmalloc(size * 2); + } + else if (pos == size) { + size += 16; + buff = xrealloc(buff, size * 2); + } + buff[pos] = c; + pos += 1; + } + + if (pos != 0) { + char *res; + if (discard) res = NULL; + else { + res = cet_str_uni_to_utf8(buff, pos); + res = lrtrim(res); + if (*res == '\0') { + xfree(res); + res = NULL; + } + } + xfree(buff); + return res; + } + else + return NULL; +} + +static void +write_wcstr(const char *str) +{ + if (str && *str) { + int bytes, value; + char *cin = (char *)str; + char *ce = cin + strlen(cin); + while (cin < ce) { + cet_utf8_to_ucs4(cin, &bytes, &value); + cin += bytes; + gbfputint16(value, fout); + } + } + gbfputint16(0, fout); +} + +static int +read_until_wcstr(const char *str) +{ + char *buff; + int len, sz; + int eos = 0, res = 0; + + len = strlen(str); + sz = (len + 1) * 2; + buff = xcalloc(sz, 1); + + while (! gbfeof(fin)) { + + char c = gbfgetc(fin); + memmove(buff, buff + 1, sz - 1); + buff[sz - 1] = c; + + if (c == 0) { + eos++; + if (eos >= 2) { /* two or more zero bytes => end of string */ + char *test = cet_str_uni_to_utf8((short *)buff, len); + if (test) { + res = (strcmp(str, test) == 0); + xfree(test); + if (res) break; + } + } + } + else eos = 0; + } + xfree(buff); + return res; +} + +static void +destinator_read_poi(void) +{ + waypoint *wpt; + int count = 0; + + gbfrewind(fin); + + while (! (gbfeof(fin))) { + char *str, *hnum; + double ll; + garmin_fs_t *gmsd; + + if (count == 0) { + str = read_wcstr(0); + if ((str == NULL) || (strcmp(str, DST_DYN_POI) != 0)) + fatal(MYNAME "_poi: Invalid record header!\n"); + xfree(str); + } + else if (! read_until_wcstr(DST_DYN_POI)) break; + + count++; + + wpt = waypt_new(); + + wpt->shortname = read_wcstr(0); + wpt->notes = read_wcstr(0); /* comment */ + + hnum = read_wcstr(0); /* house number */ + + str = read_wcstr(0); /* street */ + if (!str) { + str = hnum; + hnum = NULL; + } + if (str) { + gmsd = gmsd_init(wpt); + if (hnum) { + str = xstrappend(str, " "); + str = xstrappend(str, hnum); + } + GMSD_SET(addr, str); + } + + if ((str = read_wcstr(0))) { /* city */ + gmsd = gmsd_init(wpt); + GMSD_SET(city, str); + } + + if (hnum) xfree(hnum); + + (void) read_wcstr(1); /* unknown */ + + if ((str = read_wcstr(0))) { /* postcode */ + gmsd = gmsd_init(wpt); + GMSD_SET(postal_code, str); + } + + (void) read_wcstr(1); /* unknown */ + + (void) gbfgetdbl(fin); + + wpt->longitude = gbfgetdbl(fin); + wpt->latitude = gbfgetdbl(fin); + ll = gbfgetdbl(fin); + if (ll != wpt->longitude) + fatal(MYNAME "_poi: Invalid file!\n"); + ll = gbfgetdbl(fin); + if (ll != wpt->latitude) + fatal(MYNAME "_poi: Invalid file!\n"); + + waypt_add(wpt); + } +} + +static void +destinator_read_rte(void) +{ + int count = 0; + route_head *rte = NULL; + + gbfrewind(fin); + + while (! (gbfeof(fin))) { + char *str; + waypoint *wpt; + + if (count == 0) { + str = read_wcstr(0); + if ((str == NULL) || (strcmp(str, DST_ITINERARY) != 0)) + fatal(MYNAME "_itn: Invalid record header!\n"); + xfree(str); + } + else if (! read_until_wcstr(DST_ITINERARY)) break; + + count++; + + wpt = waypt_new(); + + wpt->shortname = read_wcstr(0); + wpt->notes = read_wcstr(0); + + (void) gbfgetint32(fin); + (void) gbfgetdbl(fin); + (void) gbfgetdbl(fin); + + wpt->longitude = gbfgetdbl(fin); + wpt->latitude = gbfgetdbl(fin); + if (gbfgetdbl(fin) != wpt->longitude) + fatal(MYNAME "_itn: Invalid file!\n"); + if (gbfgetdbl(fin) != wpt->latitude) + fatal(MYNAME "_itn: Invalid file!\n"); + + if (! rte) { + rte = route_head_alloc(); + route_add_head(rte); + } + route_add_wpt(rte, wpt); + + (void) gbfgetdbl(fin); + (void) gbfgetdbl(fin); + } +} + +static void +destinator_read_trk(void) +{ + char TXT[4] = "TXT"; + int recno = -1; + route_head *trk = NULL; + + gbfrewind(fin); + + while (! (gbfeof(fin))) { + waypoint *wpt; + struct tm tm; + char buff[20]; + int date; + double time; + + recno++; + + if (gbfeof(fin)) break; + + wpt = waypt_new(); + + wpt->longitude = gbfgetdbl(fin); + wpt->latitude = gbfgetdbl(fin); + wpt->altitude = gbfgetdbl(fin); + + (void) gbfgetdbl(fin); /* unknown */ + (void) gbfgetdbl(fin); /* unknown */ + (void) gbfgetdbl(fin); /* unknown */ + + wpt->fix = gbfgetint32(fin); + wpt->sat = gbfgetint32(fin); + + gbfseek(fin, 12 * sizeof(gbint32), SEEK_CUR); /* SAT info */ + + date = gbfgetint32(fin); + time = gbfgetflt(fin); + + gbfseek(fin, 2 * 12, SEEK_CUR); /* SAT info */ + + gbfread(TXT, 1, 3, fin); + if (strcmp(TXT, "TXT") != 0) + fatal(MYNAME "_trk: No (or unknown) file!\n"); + + gbfseek(fin, 13, SEEK_CUR); /* unknown */ + + memset(&tm, 0, sizeof(tm)); + + snprintf(buff, sizeof(buff), "%06d%.f", date, time); + strptime(buff, "%d%m%y%H%M%S", &tm); + wpt->creation_time = mkgmtime(&tm); + wpt->microseconds = ((int)time % 1000) * 1000; + + if ((wpt->sat > 0) && (wpt->fix > 0)) { + + wpt->fix++; + + if (! trk) { + trk = route_head_alloc(); + track_add_head(trk); + } + + track_add_wpt(trk, wpt); + } + else + waypt_free(wpt); + } +} + +static void +destinator_read(void) +{ + int i0, i1; + double d0, d1; + char buff[16]; + + gbfread(buff, sizeof(buff), 1, fin); + i0 = le_read32(&buff[0]); + i1 = le_read32(&buff[4]); + + if ((i0 == 0x690043) && (i1 == 0x790074)) { + if (data_type != rtedata) + warning(MYNAME ": Using Destinator Itinerary Format!\n"); + destinator_read_rte(); + } + else if ((i0 == 0x790044) && (i1 == 0x61006e)) { + if (data_type != wptdata) + warning(MYNAME ": Using Destinator POI Format!\n"); + destinator_read_poi(); + } + else { + if (data_type != trkdata) + warning(MYNAME ": Using Destinator Tracklog Format!\n"); + + le_read64(&d0, &buff[0]); + le_read64(&d1, &buff[8]); + if ((fabs(d0) > 180) || (fabs(d1) > 90)) + fatal(MYNAME ": No Destinator (.dat) file!\n"); + destinator_read_trk(); + } +} + +/*******************************************************************************/ +/* WRITER */ +/*-----------------------------------------------------------------------------*/ + +static void +destinator_wpt_disp(const waypoint *wpt) +{ + garmin_fs_t *gmsd = GMSD_FIND(wpt); + + write_wcstr(DST_DYN_POI); + write_wcstr((wpt->shortname) ? wpt->shortname : "WPT"); + write_wcstr((wpt->notes) ? wpt->notes : wpt->description); + + write_wcstr(NULL); /* house number */ + write_wcstr(GMSD_GET(addr, NULL)); /* street */ + write_wcstr(GMSD_GET(city, NULL)); /* city */ + write_wcstr(NULL); /* unknown */ + write_wcstr(GMSD_GET(postal_code, NULL)); /* postcode */ + write_wcstr(NULL); /* unknown */ + + gbfputint32(0, fout); + gbfputint32(0, fout); + + gbfputdbl(wpt->longitude, fout); + gbfputdbl(wpt->latitude, fout); + gbfputdbl(wpt->longitude, fout); + gbfputdbl(wpt->latitude, fout); + + gbfputdbl(0, fout); + gbfputdbl(0, fout); +} + +static void +destinator_trkpt_disp(const waypoint *wpt) +{ + int i; + + gbfputdbl(wpt->longitude, fout); + gbfputdbl(wpt->latitude, fout); + gbfputdbl(wpt->altitude, fout); + gbfputdbl(0, fout); + gbfputdbl(0, fout); + gbfputdbl(0, fout); + gbfputint32(wpt->fix > fix_unknown ? wpt->fix - 1 : 0, fout); + gbfputint32(wpt->sat, fout); + for (i = 0; i < 12; i++) gbfputint32(0, fout); + + if (wpt->creation_time) { + struct tm tm; + double time; + int date; + + tm = *gmtime(&wpt->creation_time); + tm.tm_mon += 1; + tm.tm_year -= 100; + date = ((int)tm.tm_mday * 10000) + ((int)tm.tm_mon * 100) + tm.tm_year; + gbfputint32(date, fout); + + time = ((int)tm.tm_hour * 10000) + ((int)tm.tm_min * 100) + tm.tm_sec; + time = (time * 1000) + (wpt->microseconds / 1000); + gbfputflt(time, fout); + } + else { + gbfputint32(0, fout); /* Is this invalid ? */ + gbfputflt(0, fout); + } + + for (i = 0; i < 12; i++) gbfputint16(0, fout); + gbfputcstr("TXT", fout); + for (i = 0; i < 12; i++) gbfputc(0, fout); +} + +static void +destinator_rtept_disp(const waypoint *wpt) +{ + write_wcstr(DST_ITINERARY); + write_wcstr((wpt->shortname) ? wpt->shortname : "RTEPT"); + write_wcstr((wpt->notes) ? wpt->notes : wpt->description); + + gbfputint32(0, fout); + gbfputdbl(0, fout); + gbfputdbl(0, fout); + + gbfputdbl(wpt->longitude, fout); + gbfputdbl(wpt->latitude, fout); + gbfputdbl(wpt->longitude, fout); + gbfputdbl(wpt->latitude, fout); + + gbfputdbl(0, fout); + gbfputdbl(0, fout); +} + +/******************************************************************************* +* %%% global callbacks called by gpsbabel main process %%% * +*******************************************************************************/ + +static void +destinator_rd_init(const char *fname) +{ + fin = gbfopen_le(fname, "rb", MYNAME); +} + +static void +destinator_rd_deinit(void) +{ + gbfclose(fin); +} + +static void +destinator_read_poi_wrapper(void) +{ + data_type = wptdata; + destinator_read(); +} + +static void +destinator_read_rte_wrapper(void) +{ + data_type = rtedata; + destinator_read(); +} + +static void +destinator_read_trk_wrapper(void) +{ + data_type = trkdata; + destinator_read(); +} + +static void +destinator_wr_init(const char *fname) +{ + fout = gbfopen_le(fname, "wb", MYNAME); +} + +static void +destinator_wr_deinit(void) +{ + gbfclose(fout); +} + +static void +destinator_write_poi(void) +{ + waypt_disp_all(destinator_wpt_disp); +} + +static void +destinator_write_rte(void) +{ + route_disp_all(NULL, NULL, destinator_rtept_disp); +} + +static void +destinator_write_trk(void) +{ + track_disp_all(NULL, NULL, destinator_trkpt_disp); +} + +/**************************************************************************/ + +ff_vecs_t destinator_poi_vecs = { + ff_type_file, + { + ff_cap_read | ff_cap_write /* waypoints */, + ff_cap_none /* tracks */, + ff_cap_none /* routes */ + }, + destinator_rd_init, + destinator_wr_init, + destinator_rd_deinit, + destinator_wr_deinit, + destinator_read_poi_wrapper, + destinator_write_poi, + NULL, + destinator_args, + CET_CHARSET_UTF8, 1 /* fixed */ +}; + +ff_vecs_t destinator_itn_vecs = { + ff_type_file, + { + ff_cap_none /* waypoints */, + ff_cap_none /* tracks */, + ff_cap_read | ff_cap_write /* routes */ + }, + destinator_rd_init, + destinator_wr_init, + destinator_rd_deinit, + destinator_wr_deinit, + destinator_read_rte_wrapper, + destinator_write_rte, + NULL, + destinator_args, + CET_CHARSET_UTF8, 1 /* fixed */ +}; + +ff_vecs_t destinator_trl_vecs = { + ff_type_file, + { + ff_cap_none /* waypoints */, + ff_cap_read | ff_cap_write /* tracks */, + ff_cap_none /* routes */ + }, + destinator_rd_init, + destinator_wr_init, + destinator_rd_deinit, + destinator_wr_deinit, + destinator_read_trk_wrapper, + destinator_write_trk, + NULL, + destinator_args, + CET_CHARSET_UTF8, 1 /* fixed */ +}; + +/**************************************************************************/ diff --git a/dg-100.c b/dg-100.c new file mode 100644 index 000000000..051857858 --- /dev/null +++ b/dg-100.c @@ -0,0 +1,689 @@ +/* + + GlobalSat DG-100 GPS data logger download. + + Copyright (C) 2007 Mirko Parthey, mirko.parthey@informatik.tu-chemnitz.de + Copyright (C) 2005-2008 Robert Lipe, robertlipe@gpsbabel.org + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +/* + DG-100 communication protocol specification: + http://www.usglobalsat.com/forum/topic.asp?TOPIC_ID=607#1375 + */ + +#include "defs.h" +#include + +#include "gbser.h" +#include +#include + +#define MYNAME "DG-100" + +static void *serial_handle; + +/* maximum frame size observed so far: 1817 bytes + * (dg100cmd_getfileheader returning 150 entries) + * dg100cmd_getfileheader is the only answer type of variable length, + * answers of other types are always shorter than 1817 bytes */ +#define FRAME_MAXLEN 4096 + +enum dg100_command_id { + dg100cmd_getconfig = 0xB7, + dg100cmd_setconfig = 0xB8, + dg100cmd_getfileheader = 0xBB, + dg100cmd_getfile = 0xB5, + dg100cmd_erase = 0xBA, + dg100cmd_getid = 0xBF, + dg100cmd_setid = 0xC0, + dg100cmd_gpsmouse = 0xBC +}; + +struct dg100_command { + int id; + int sendsize; + int recvsize; + int trailing_bytes; + const char *text; /* Textual description for debugging */ +}; + +struct dg100_command dg100_commands[] = { + { dg100cmd_getconfig, 0, 44+2, 2, "getconfig" }, + { dg100cmd_setconfig, 41, 4+2, 2, "setconfig" }, + /* the getfileheader answer has variable length, -1 is a dummy value */ + { dg100cmd_getfileheader, 2, -1 , 2, "getfileheader" }, + { dg100cmd_getfile, 2, 1024+2, 2, "getfile" }, + { dg100cmd_erase, 2, 4+2, 2, "erase" }, + { dg100cmd_getid, 0, 8+2, 2, "getid" }, + { dg100cmd_setid, 8, 4+2, 2, "setid" }, + { dg100cmd_gpsmouse, 1, 0 , 0, "gpsmouse" } +}; +const unsigned dg100_numcommands = sizeof(dg100_commands) / sizeof(dg100_commands[0]); + +/* TODO: use obstacks or vmem_t instead? */ +struct dynarray16 { + unsigned count; /* number of elements used */ + unsigned limit; /* number of elements allocated */ + gbint16 *data; +}; + +/* helper functions */ +static struct dg100_command * +dg100_findcmd(int id) +{ + unsigned int i; + + /* linear search should be OK as long as dg100_numcommands is small */ + for (i = 0; i < dg100_numcommands; i++) { + if (dg100_commands[i].id == id) + return(&dg100_commands[i]); + } + + return NULL; +} + +static void +dynarray16_init(struct dynarray16 *a, unsigned limit) +{ + a->count = 0; + a->limit = limit; + a->data = xmalloc(sizeof(a->data[0]) * a->limit); +} + +static gbint16 * +dynarray16_alloc(struct dynarray16 *a, unsigned n) +{ + unsigned int i; + unsigned int need; + const unsigned elements_per_chunk = 4096 / sizeof(a->data[0]); + + i = a->count; + a->count += n; + + need = a->count - a->limit; + if (need > 0) { + need = (need > elements_per_chunk) ? need : elements_per_chunk; + a->limit += need; + xrealloc(a->data, sizeof(a->data[0]) * a->limit); + } + return(a->data + i); +} + +static time_t +bintime2utc(int date, int time) +{ + struct tm gpstime; + + gpstime.tm_sec = time % 100; + time /= 100; + gpstime.tm_min = time % 100; + time /= 100; + gpstime.tm_hour = time; + + /* + * GPS year: 2000+; struct tm year: 1900+ + * GPS month: 1-12, struct tm month: 0-11 + */ + gpstime.tm_year = date % 100 + 100; + date /= 100; + gpstime.tm_mon = date % 100 - 1; + date /= 100; + gpstime.tm_mday = date; + + return(mkgmtime(&gpstime)); +} + +static void +dg100_debug(const char *hdr, int include_nl, size_t sz, unsigned char *buf) +{ + unsigned int i; + + /* Only give byte dumps for higher debug levels */ + if (global_opts.debug_level < 5) { + return; + } + + fprintf(stderr, "%s", hdr); + + for (i = 0; i < sz; i++) { + fprintf(stderr, "%02x ", buf[i]); + } + + if (include_nl) { + fprintf(stderr, "\n"); + } +} + +static void +dg100_log(const char *fmt, ...) +{ + va_list ap; + va_start (ap, fmt); + if (global_opts.debug_level < 1) { + return; + } + + vfprintf(stderr, fmt, ap); + va_end(ap); +} + + +/* TODO: check whether negative lat/lon (West/South) are handled correctly */ +static float +bin2deg(int val) +{ + /* Assume that val prints in decimal digits as [-]dddmmffff + * ddd: degrees + * mm: the integer part of minutes + * ffff: the fractional part of minutes (decimal fraction 0.ffff) + */ + + float deg; + int deg_int, min_scaled, isneg; + unsigned absval; + + /* avoid division of negative integers, + * which has platform-dependent results */ + absval = abs(val); + isneg = (val < 0); + + deg_int = absval / 1000000; /* extract ddd */ + min_scaled = absval % 1000000; /* extract mmffff (minutes * 10^4) */ + deg = deg_int + (double) min_scaled / (10000 * 60); + + /* restore the sign */ + deg = isneg ? -deg : deg; + return(deg); +} + +static void +process_gpsfile(gbuint8 data[], route_head *track) +{ + const int recordsizes[3] = {8, 20, 32}; + int i, style, recsize; + int lat, lon, bintime, bindate; + waypoint *wpt; + + /* the first record of each file is always full-sized; its style field + * determines the format of all subsequent records in the file */ + style = be_read32(data + 28); + if (style > 2) { + fprintf(stderr, "unknown GPS record style %d", style); + return; + } + recsize = recordsizes[style]; + + for (i = 0; i <= 2048 - recsize; i += (i == 0) ? 32 : recsize) { + + lat = be_read32(data + i + 0); + lon = be_read32(data + i + 4); + + /* skip invalid trackpoints (blank records) */ + if (lat == -1 && lon == -1) { + continue; + } + + wpt = waypt_new(); + wpt->latitude = bin2deg(lat); + wpt->longitude = bin2deg(lon); + + if (style >= 1) { + bintime = be_read32(data + i + 8); + bindate = be_read32(data + i + 12); + wpt->creation_time = bintime2utc(bindate, bintime); + /* The device presents the speed as a fixed-point number + * with a scaling factor of 100, in km/h. + * The waypoint struct wants the speed as a + * floating-point number, in m/s. */ + wpt->speed = KPH_TO_MPS(be_read32(data + i + 16) / 100.0); + wpt->wpt_flags.speed = 1; + } + + if (style >= 2) { + wpt->altitude = be_read32(data + i + 20) / 10000.0; + } + + track_add_wpt(track, wpt); + } +} + +static gbuint16 +dg100_checksum(gbuint8 buf[], int count) +{ + gbuint16 sum = 0; + int i; + + for (i = 0; i < count; i++) { + sum += buf[i]; + } + sum &= (1<<15) - 1; + + return(sum); +} + +/* communication functions */ +static size_t +dg100_send(gbuint8 cmd, const void *payload, size_t count) +{ + gbuint8 frame[FRAME_MAXLEN]; + gbuint16 checksum, payload_len; + size_t framelen, param_len; + int n; + + param_len = count; + payload_len = 1 + count; + /* Frame length calculation: + * frame start sequence(2), payload length field(2), command id(1), + * param(variable length), + * checksum(2), frame end sequence(2) */ + framelen = 2 + 2 + 1 + count + 2 + 2; + assert(framelen <= FRAME_MAXLEN); + + /* create frame head + command */ + be_write16(frame + 0, 0xA0A2); + be_write16(frame + 2, payload_len); + frame[4] = cmd; + + /* copy payload */ + memcpy(frame + 5, payload, count); + + /* create frame tail */ + checksum = dg100_checksum(frame + 4, framelen - 8); + be_write16(frame + framelen - 4, checksum); + be_write16(frame + framelen - 2, 0xB0B3); + + n = gbser_write(serial_handle, frame, framelen); + + if (global_opts.debug_level) { + struct dg100_command *cmdp = dg100_findcmd(cmd); + + dg100_debug(n == 0 ? "Sent: " : "Error Sending:", + 1, framelen, frame); + dg100_log("TX: Frame Start %02x %02x Payload_Len %04x Cmd: %s\n", + frame[0], frame[1], payload_len, cmdp->text); + } + + if (n == gbser_ERROR) { + fatal("dg_100_send: write failed\n"); + } + return (n); +} + +static int +dg100_recv_byte() +{ + int result; + + /* allow for a delay of 40s; + * erasing the whole DG-100 memory takes about 21s */ + result = gbser_readc_wait(serial_handle, 40000); + switch(result){ + case gbser_ERROR: + fatal("dg100_recv_byte(): error reading one byte\n"); + case gbser_NOTHING: + fatal("dg100_recv_byte(): read timeout\n"); + } + return result; +} + +/* payload returns a pointer into a static buffer (which also contains the + * framing around the data), so the caller must copy the data before calling + * this function again */ +static int +dg100_recv_frame(struct dg100_command **cmdinfo_result, gbuint8 **payload) +{ + static gbuint8 buf[FRAME_MAXLEN]; + gbuint16 frame_start_seq, payload_len_field; + gbuint16 payload_end_seq, payload_checksum, frame_end_seq; + gbuint16 frame_head, numheaders, sum; + gbuint8 c, cmd; + int i, param_len, frame_len; + struct dg100_command *cmdinfo; + + /* consume input until frame head sequence 0xA0A2 was received */ + frame_head = 0; + dg100_debug("Receiving ", 0, 0, NULL); + do { + c = dg100_recv_byte(); + dg100_debug("", 0, 1, &c); + frame_head <<= 8; + frame_head |= c; + + } while (frame_head != 0xA0A2); + + be_write16(buf + 0, frame_head); + + /* To read the remaining data, we need to know how long the frame is. + * + * The obvious source of this information would be the payload length + * field, but the spec says that this field should be ignored in answers. + * Indeed, its value differs from the actual payload length. + * + * We could scan for the frame end sequences, + * but there is no guarantee that they do not appear within valid data. + * + * This means we can only calculate the length using information from + * the beginning of the frame, other than the payload length. + * + * The solution implemented here is to derive the frame length from the + * Command ID field, which is more of an answer ID. This is possible + * since for each answer ID, the frame length is either constant or it + * can be derived from the first two bytes of payload data. + */ + + /* read Payload Length, Command ID, and two further bytes */ + for (i = 2; i < 7; i++) { + buf[i] = dg100_recv_byte(); + dg100_debug("", 0, 1, &buf[i]); + } + + payload_len_field = be_read16(buf + 2); + cmd = buf[4]; + + /* + * getconfig/setconfig have the same answer ID - + * this seems to be a firmware bug we must work around. + * Distinguish them by the (otherwise ignored) Payload Len field, + * which was observed as 53 for getconfig and 5 for setconfig. + */ + if (cmd == dg100cmd_getconfig && payload_len_field <= 20) { + cmd = dg100cmd_setconfig; + } + + cmdinfo = dg100_findcmd(cmd); + if (!cmdinfo) { + /* TODO: consume data until frame end signature, + * then report failure to the caller? */ + fatal("unknown answer ID %02x\n", cmd); + } + + param_len = cmdinfo->recvsize; + + /* + * the getfileheader answer has a varying param_len, + * we need to calculate it + */ + if (cmd == dg100cmd_getfileheader) { + numheaders = be_read16(buf + 5); + param_len = 2 + 2 + 12 * numheaders + 2; + } + + /* Frame length calculation: + * frame start sequence(2), payload length field(2), command id(1), + * param(variable length), + * payload end seqence(2), checksum(2), frame end sequence(2) */ + frame_len = 2 + 2 + 1 + param_len + 2 + 2 + 2; + + if (frame_len > FRAME_MAXLEN) { + fatal("frame too large (frame_len=%d, FRAME_MAXLEN=%d)\n", + frame_len, FRAME_MAXLEN); + } + + /* TODO: Since we know how long the frame should be, we could try to + * read the rest of the frame at once using gbser_read_wait(). */ +#if 0 + for (i = 7; i < frame_len; i++) { + buf[i] = dg100_recv_byte(); + dg100_debug("", 0, 1, &buf[i]); + } +#else + i = gbser_read_wait(serial_handle, &buf[7], frame_len - 7, 1000); + dg100_debug("", 0, frame_len - 7, &buf[7]); + if (i < frame_len - 7) { + fatal("Expected to read %d bytes, but got %d\n", + frame_len - 7, i); + } +#endif + + frame_start_seq = be_read16(buf + 0); + payload_len_field = be_read16(buf + 2); + payload_end_seq = be_read16(buf + frame_len - 6); + payload_checksum = be_read16(buf + frame_len - 4); + frame_end_seq = be_read16(buf + frame_len - 2); + + dg100_log("RX: Start %04x Len %04x Cmd: %s\n", + frame_start_seq, payload_len_field, cmdinfo->text); + + /* calculate checksum */ + sum = dg100_checksum(buf + 4, frame_len - 8); + if (sum != payload_checksum) { + fatal("checksum mismatch: data sum is 0x%04x, checksum received is 0x%04x\n", + sum, payload_checksum); + } + + /* + * TODO: check signatures; + * on failure, flush input or scan for end sequence + */ + + *cmdinfo_result = cmdinfo; + *payload = buf + 5; + dg100_debug("\n", 0, 0, &buf[i]); + return(param_len); +} + +/* return value: number of bytes copied into buf, -1 on error */ +static int +dg100_recv(gbuint8 expected_id, void *buf, unsigned int len) +{ + int n; + struct dg100_command *cmdinfo; + gbuint8 *data; + unsigned int copysize, trailing_bytes; + + n = dg100_recv_frame(&cmdinfo, &data); + + /* check whether the received frame matches the expected answer type */ + if (cmdinfo->id != expected_id) { + fprintf(stderr, "ERROR: answer type %02x, expecting %02x", cmdinfo->id, expected_id); + return -1; + } + + trailing_bytes = cmdinfo->trailing_bytes; + copysize = n - trailing_bytes; + + /* check for buffer overflow */ + if (len < copysize) { + fprintf(stderr, "ERROR: buffer too small, size=%d, need=%d", len, copysize); + return -1; + } + + memcpy(buf, data, copysize); + return(copysize); +} + +/* the number of bytes to be sent is determined by cmd, + * count is the size of recvbuf */ +static int +dg100_request(gbuint8 cmd, const void *sendbuf, void *recvbuf, size_t count) +{ + struct dg100_command *cmdinfo; + int n, i, frames, fill; + gbuint8 *buf; + + cmdinfo = dg100_findcmd(cmd); + assert (cmdinfo != NULL); + dg100_send(cmd, sendbuf, cmdinfo->sendsize); + + /* the number of frames the answer will comprise */ + frames = (cmd == dg100cmd_getfile) ? 2 : 1; + /* alias pointer for easy typecasting */ + buf = recvbuf; + fill = 0; + for (i = 0; i < frames; i++) { + n = dg100_recv(cmd, buf + fill, count - fill); + if (n < 0) + return(-1); + fill += n; + } + return(fill); +} + +/* higher level communication functions */ +static void +dg100_getfileheaders(struct dynarray16 *headers) +{ + gbuint8 request[2]; + gbuint8 answer[FRAME_MAXLEN]; + int seqnum; + gbint16 numheaders, nextheader, *h; + int i, offset; + + nextheader = 0; + do { + /* request the next batch of headers */ + be_write16(request, nextheader); + dg100_request(dg100cmd_getfileheader, request, answer, sizeof(answer)); + + /* process the answer */ + numheaders = be_read16(answer); + nextheader = be_read16(answer + 2); + dg100_log("found %d headers, nextheader=%d\n", + numheaders, nextheader); + + h = dynarray16_alloc(headers, numheaders); + for (i = 0; i < numheaders; i++) { + offset = 4 + i * 12; + seqnum = be_read32(answer + offset + 8); + h[i] = seqnum; + if (global_opts.debug_level) { + int time = be_read32(answer + offset); + int date = be_read32(answer + offset + 4); + time_t ti = bintime2utc(date, time); + dg100_log("Header #%d: Seq: %d Time: %s", + i, seqnum, ctime(&ti)); + } + } + } while (nextheader != 0); +} + +static void +dg100_getfile(gbint16 num, route_head *track) +{ + gbuint8 request[2]; + gbuint8 answer[2048]; + + be_write16(request, num); + dg100_request(dg100cmd_getfile, request, answer, sizeof(answer)); + process_gpsfile(answer, track); +} + +static void +dg100_getfiles() +{ + unsigned int i; + int filenum; + struct dynarray16 headers; + route_head *track; + + track = route_head_alloc(); + track->rte_name = xstrdup("DG-100 tracklog"); + track->rte_desc = xstrdup("DG-100 GPS tracklog data"); + track_add_head(track); + + /* maximum number of headers observed so far: 672 + * if necessary, the dynarray will grow even further */ + dynarray16_init(&headers, 1024); + + dg100_getfileheaders(&headers); + + for (i = 0; i < headers.count; i++) { + filenum = headers.data[i]; + dg100_getfile(filenum, track); + } +} + +static int +dg100_erase() +{ + gbuint8 request[2] = { 0xFF, 0xFF }; + gbuint8 answer[4]; + + dg100_request(dg100cmd_erase, request, answer, sizeof(answer)); + if (be_read32(answer) != 1) { + fprintf(stderr, "dg100_erase() FAILED\n"); + return(-1); + } + return(0); +} + +/* GPSBabel integration */ + +static char *erase; + +static +arglist_t dg100_args[] = { + { "erase", &erase, "Erase device data after download", + "0", ARGTYPE_BOOL, ARG_NOMINMAX }, + ARG_TERMINATOR +}; + +/******************************************************************************* +* %%% global callbacks called by gpsbabel main process %%% * +*******************************************************************************/ + +static void +dg100_rd_init(const char *fname) +{ + if (serial_handle = gbser_init(fname), NULL == serial_handle) { + fatal(MYNAME ": Can't open port '%s'\n", fname); + } + if (gbser_set_speed(serial_handle, 115200) != gbser_OK) { + fatal(MYNAME ": Can't configure port '%s'\n", fname); + } +} + +static void +dg100_rd_deinit(void) +{ + gbser_deinit(serial_handle); + serial_handle = NULL; +} + +static void +dg100_read(void) +{ + dg100_getfiles(); + if (*erase == '1') { + dg100_erase(); + } +} + +/**************************************************************************/ + +// capabilities below means: we can only read tracks + +ff_vecs_t dg100_vecs = { + ff_type_serial, + { + ff_cap_none /* waypoints */, + ff_cap_read /* tracks */, + ff_cap_none /* routes */ + }, + dg100_rd_init, + NULL, + dg100_rd_deinit, + NULL, + dg100_read, + NULL, + NULL, + dg100_args, + CET_CHARSET_ASCII, 0 /* ascii is the expected character set */ + /* not fixed, can be changed through command line parameter */ +}; +/**************************************************************************/ diff --git a/discard.c b/discard.c index d8f1942c5..0a8d29e4d 100644 --- a/discard.c +++ b/discard.c @@ -26,8 +26,10 @@ static char *hdopopt = NULL; static char *vdopopt = NULL; static char *andopt = NULL; +static char *satopt = NULL; static double hdopf; static double vdopf; +static int satpf; static gpsdata_type what; static route_head *head; @@ -39,6 +41,8 @@ arglist_t fix_args[] = { "-1.0", ARGTYPE_END_REQ | ARGTYPE_FLOAT, ARG_NOMINMAX}, {"hdopandvdop", &andopt, "Link hdop and vdop supression with AND", NULL, ARGTYPE_BOOL, ARG_NOMINMAX}, + {"sat", &satopt, "Minimium sats to keep waypoints", + "-1.0", ARGTYPE_BEGIN_REQ | ARGTYPE_INT, ARG_NOMINMAX}, ARG_TERMINATOR }; @@ -51,6 +55,7 @@ fix_process_wpt(const waypoint *wpt) int del = 0; int delh = 0; int delv = 0; + waypoint *waypointp = (waypoint *) wpt; if ((hdopf >= 0.0) && (waypointp->hdop > hdopf)) @@ -62,6 +67,9 @@ fix_process_wpt(const waypoint *wpt) del = delh && delv; else del = delh || delv; + + if ((satpf >= 0) && (waypointp->sat < satpf)) + del = 1; if (del) { switch(what) { @@ -116,6 +124,12 @@ fix_init(const char *args) vdopf = atof(vdopopt); else vdopf = -1.0; + + if (satopt) + satpf = atoi(satopt); + else + satpf = -1; + } filter_vecs_t discard_vecs = { diff --git a/dmtlog.c b/dmtlog.c index 9a88c50aa..0d11cf2ca 100644 --- a/dmtlog.c +++ b/dmtlog.c @@ -2,7 +2,7 @@ Support for TrackLogs digital mapping (.trl) files, - Copyright (C) 2006 Olaf Klein, o.b.klein@gpsbabel.org + Copyright (C) 2006,2007 Olaf Klein, o.b.klein@gpsbabel.org This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -308,14 +308,51 @@ tlog3b_xgcb_wpten(const char *args, const char **unused) } +static char * +read_str(gbfile *f) +{ + int i; + char *res; + + i = gbfgetc(f); + if (i == 0xff) i = gbfgetint16(f); + + res = xmalloc(i + 1); + res[i] = '\0'; + if (i) gbfread(res, 1, i, f); + + return res; +} + +static void +write_str(const char *str, gbfile *f) +{ + if (str && *str) { + int len = strlen(str); + if (len > 0xfe) { +#if 0 + if (len > 0x7fff) len = 0x7fff; + gbfputc((unsigned char) 0xff, f); + gbfputint16(len, f); +#else + len = 0xfe; + gbfputc(len, f); +#endif + } + else gbfputc(len, f); + gbfwrite(str, len, 1, f); + } + else gbfputc(0, f); +} + static int read_datum(gbfile *f) { int res; char *d, *g; - d = gbfgetpstr(f); - g = gbfgetpstr(f); + d = read_str(f); + g = read_str(f); res = GPS_Lookup_Datum_Index(d); @@ -348,10 +385,9 @@ read_CTrackFile(const int version) if ((u1 != 0x0a) || (strncmp("CTrackFile", buf, 10) != 0)) fatal(MYNAME ": Unknown or invalid track file.\n"); - if (version == 8) { - for (i = 1; i <= 9; i++) - gbfread(buf, 1, 4, fin); - } + if (version == 8) + gbfseek(fin, 36, SEEK_CUR); /* skip unknown 36 bytes */ + ver = gbfgetint32(fin); if (ver != version) fatal(MYNAME ": Unknown or invalid track file (%d).\n", ver); @@ -365,8 +401,8 @@ read_CTrackFile(const int version) /* S1 .. S9: comments, hints, jokes, aso */ for (i = 0; i < 9; i++) { - int c = gbfgetc(fin); - gbfseek(fin, c, SEEK_CUR); + char *s = read_str(fin); + xfree(s); } tcount = gbfgetint32(fin); @@ -401,17 +437,55 @@ read_CTrackFile(const int version) track_add_wpt(track, wpt); if (version == 8) - gbfseek(fin, 34, SEEK_CUR); + gbfseek(fin, 34, SEEK_CUR); /* skip unknown 34 bytes */ } - wcount = gbfgetint32(fin); - - if (wcount == 0) return; - if (version == 8) { - warning(MYNAME ": We don't yet support waypoints for this file version!\n"); + + i = gbfgetint16(fin); + i = gbfgetc(fin); + if (i == 0) return; + + gbfungetc(i, fin); + datum = read_datum(fin); + + (void) gbfgetint16(fin); + (void) gbfgetint32(fin); + + gbfread(buf, 1, 9, fin); + if (strncmp(buf, "CWayPoint", 9) != 0) { + warning(MYNAME ": Unsupported waypoint structure!\n"); + return; + } + + while (! gbfeof(fin)) { + waypoint *wpt; + + i = gbfgetc(fin); + if (i == 0) break; + + gbfungetc(i, fin); + datum = read_datum(fin); + + wpt = waypt_new(); + + wpt->latitude = gbfgetdbl(fin); + wpt->longitude = gbfgetdbl(fin); + wpt->altitude = gbfgetdbl(fin); + + gbfseek(fin, 36, SEEK_CUR); /* skip unknown 36 bytes */ + + wpt->notes = read_str(fin); + wpt->description = read_str(fin); + (void) gbfgetint16(fin); + + waypt_add(wpt); + } return; } + + wcount = gbfgetint32(fin); + if (wcount == 0) return; datum = read_datum(fin); @@ -421,9 +495,6 @@ read_CTrackFile(const int version) wcount--; - if (version == 8) - datum = read_datum(fin); - wpt = waypt_new(); wpt->latitude = gbfgetdbl(fin); @@ -437,7 +508,9 @@ read_CTrackFile(const int version) // variants of shortname for (i = 0; i < namect; i++) { - char *name = gbfgetpstr(fin); + char *name; + + name = read_str(fin); if (name && *name) { switch(i) { case 0: wpt->description = xstrdup(name); break; @@ -446,9 +519,7 @@ read_CTrackFile(const int version) } xfree(name); } - if (version == 8) - gbfseek(fin, 34, SEEK_CUR); - + waypt_add(wpt); } } @@ -619,18 +690,18 @@ write_header(const route_head *trk) queue *curr, *prev; QUEUE_FOR_EACH(&trk->waypoint_list, curr, prev) count++; } - gbfputpstr(trk && trk->rte_name && *trk->rte_name ? trk->rte_name : "Name", fout); + write_str(trk && trk->rte_name && *trk->rte_name ? trk->rte_name : "Name", fout); xasprintf(&cout, "%d trackpoints and %d waypoints", count, waypt_count()); - gbfputpstr(cout, fout); + write_str(cout, fout); xfree(cout); for (i = 3; i <= 8; i++) gbfputc(ZERO, fout); - gbfputpstr("GPSBabel", fout); + write_str("GPSBabel", fout); gbfputint32(count, fout); if (count > 0) { - gbfputpstr("WGS84", fout); - gbfputpstr("WGS84", fout); + write_str("WGS84", fout); + write_str("WGS84", fout); } } @@ -670,8 +741,8 @@ wpt_cb(const waypoint *wpt) names = 1; if (wpt->description && *wpt->description) names = 2; gbfputint32(names, fout); - if (names > 1) gbfputpstr(wpt->description, fout); - gbfputpstr(wpt->shortname && *wpt->shortname ? wpt->shortname : "Name", fout); + if (names > 1) write_str(wpt->description, fout); + write_str(wpt->shortname && *wpt->shortname ? wpt->shortname : "Name", fout); } static void @@ -695,8 +766,8 @@ dmtlog_write(void) write_header(NULL); gbfputint32(waypt_count(), fout); if (waypt_count() > 0) { - gbfputpstr("WGS84", fout); - gbfputpstr("WGS84", fout); + write_str("WGS84", fout); + write_str("WGS84", fout); waypt_disp_all(wpt_cb); } } diff --git a/exif.c b/exif.c new file mode 100644 index 000000000..d81e210fa --- /dev/null +++ b/exif.c @@ -0,0 +1,490 @@ +/* + + Support for embedded Exif-GPS information. + + Copyright (C) 2008 Olaf Klein, o.b.klein@gpsbabel.org + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + +#include "defs.h" +#include "config.h" +#include "garmin_tables.h" +#include "jeeps/gpsmath.h" +#include "strptime.h" +#include + +#define MYNAME "exif" + +#define UNKNOWN_TIMESTAMP 999999999 + +typedef struct exif_tag_s { + gbuint16 tag; + gbuint16 type; + gbint32 count; + gbuint32 offs; +} exif_tag_t; + +static gbfile *fin; +static gbsize_t exif_ifd, gps_ifd; +static char byte_order; +static waypoint *wpt; +static gbsize_t fileoffs; +static char *opt_filename; +static time_t timestamp; + +static +arglist_t exif_args[] = { + {"filename", &opt_filename, "Set waypoint name to source filename.", "Y", ARGTYPE_BOOL, ARG_NOMINMAX}, + ARG_TERMINATOR +}; + +#define EXIF_IFD -1 +#define GPS_IFD -2 + +/******************************************************************************* +* %%% global callbacks called by gpsbabel main process %%% * +*******************************************************************************/ + +static void +exif_rd_init(const char *fname) +{ + fin = gbfopen_le(fname, "rb", MYNAME); +} + +static void +exif_rd_deinit(void) +{ + gbfclose(fin); +} + +#if 0 +static int +exif_tag_size(const exif_tag_t *tag) +{ + int size; + + switch(tag->type) { + case 1: + case 2: + case 7: size = 1; break; + case 3: size = 2; break; + case 4: + case 9: size = 4; break; + case 5: + case 10: size = 8; break; + default: + return 0; + } + return size * tag->count; +} +#endif + +static double +exif_read_double(const gbsize_t offs) +{ + unsigned int num, den; + + if (offs) gbfseek(fin, fileoffs + offs, SEEK_SET); + + num = gbfgetuint32(fin); + den = gbfgetuint32(fin); + if (den == 0) den = 1; + + return (double)num / den; +} + +static double +exif_read_coord(const exif_tag_t *tag) +{ + double deg, min, sec; + + deg = exif_read_double(tag->offs); + if (tag->count == 1) return deg; + + min = exif_read_double(0); + deg += (min / 60); + if (tag->count == 2) return deg; + + sec = exif_read_double(0); + deg += (sec / 3600); + + return deg; +} + +static char * +exif_read_string(const exif_tag_t *tag) +{ + if (tag->count > 4) { + gbfseek(fin, fileoffs + tag->offs, SEEK_SET); + return gbfgetcstr(fin); + } + else { + char buff[5]; + if (fin->big_endian) be_write32(buff, tag->offs); + else le_write32(buff, tag->offs); + if (tag->count < 5) buff[tag->count] = '\0'; + else buff[4] = '\0'; + return xstrdup(buff); + } +} + +static time_t +exif_read_timestamp(const exif_tag_t *tag) +{ + double hour, min, sec; + + hour = exif_read_double(tag->offs); + min = exif_read_double(0); + sec = exif_read_double(0); + + return ((int)hour * SECONDS_PER_HOUR) + ((int)min * 60) + (int)sec; +} + +static int +exif_sort_tags_cb(const void *a, const void *b) +{ + const exif_tag_t *ea = a; + const exif_tag_t *eb = b; + return (int)ea->offs - (int)eb->offs; +} + +static gbsize_t +exif_read_tags(const int ifd) +{ + int entries; + exif_tag_t *tags = NULL; + gbsize_t next_ifd = 0; + double gpsdop = unknown_alt; + char speed_ref = 'K'; + char lat_ref = '*'; + char lon_ref = '*'; + char mode = 'N'; + int datum = DATUM_WGS84; + + entries = gbfgetint16(fin); + if (entries > 0) { + int i; + tags = xmalloc(entries * sizeof(*tags)); + for (i = 0; i < entries; i++) { + tags[i].tag = gbfgetuint16(fin); + tags[i].type = gbfgetuint16(fin); + tags[i].count = gbfgetint32(fin); + tags[i].offs = gbfgetuint32(fin); + } + } + + next_ifd = gbfgetuint32(fin); + + if (entries > 0) { + int i; + char *str, *c; + struct tm tm; + + if (entries > 1) /* avoid backward seek */ + qsort(tags, entries, sizeof(*tags), exif_sort_tags_cb); + + for (i = 0; i < entries; i++) { + exif_tag_t *tag = &tags[i]; + + switch(ifd) { + case 0: + switch(tag->tag) { + case 0x8769: + exif_ifd = tag->offs; + break; + case 0x8825: + gps_ifd = tag->offs; + break; + } + break; + case 1: /* IFD1 */ + break; + case -1: /* Exif */ + switch(tag->tag) { + + case 0x9003: /* DateTimeOriginal */ + str = exif_read_string(tag); + c = strptime(str, "%Y:%m:%d %H:%M:%S", &tm); + if (c && (*c == '\0')) + wpt->creation_time = mklocaltime(&tm); + xfree(str); + break; + } + break; + case -2: /* GPS */ + switch(tag->tag) { + + case 0x0001: /* GPSLatitudeRef */ + str = exif_read_string(tag); + lat_ref = *str & 127; + xfree(str); + break; + + case 0x0002: /* GPSLatitude */ + wpt->latitude = exif_read_coord(tag); + break; + + case 0x0003: /* GPSLongitudeRef */ + str = exif_read_string(tag); + lon_ref = *str & 127; + xfree(str); + break; + + case 0x0004: /* GPSLongitude */ + wpt->longitude = exif_read_coord(tag); + break; + + case 0x0005: /* GPSAltitudeRef */ + break; + + case 0x0006: /* GPSAltitude */ + wpt->altitude = exif_read_double(tag->offs); + break; + + case 0x0007: /* GPSTimeStamp */ + timestamp = exif_read_timestamp(tag); + break; + + case 0x0008: /* GPSSatellites */ + str = exif_read_string(tag); + wpt->sat = atoi(str); + xfree(str); + break; + + case 0x000a: /* GPSMeasureMode */ + str = exif_read_string(tag); + mode = *str & 127; + xfree(str); + break; + + case 0x000b: /* GPSDOP */ + gpsdop = exif_read_double(tag->offs); + break; + + case 0x000c: /* GPSSpeedRef */ + str = exif_read_string(tag); + speed_ref = *str & 127; + xfree(str); + break; + + case 0x000d: /* GPSSpeed */ + WAYPT_SET(wpt, speed, exif_read_double(tag->offs)); + break; + + case 0x0012: /* GPSMapDatum */ + str = exif_read_string(tag); + datum = gt_lookup_datum_index(str, MYNAME); + if (datum < 0) + fatal(MYNAME ": Unknown GPSMapDatum \"%s\"!\n", str); + xfree(str); + break; + } + break; + } + } + xfree(tags); + } + + if (ifd == GPS_IFD) { + + /* Did we get our minimum data ? */ + if ((wpt->latitude == unknown_alt) || (wpt->longitude == unknown_alt)) { + warning(MYNAME ": GPSLatitude and/or GPSLongitude not set!\n"); + waypt_free(wpt); + wpt = NULL; + return 0; + } + + if WAYPT_HAS(wpt, speed) { + switch(speed_ref) { + case 'K': + wpt->speed = KPH_TO_MPS(wpt->speed); + break; + case 'M': + wpt->speed = MPH_TO_MPS(wpt->speed); + break; + case 'N': + wpt->speed = KNOTS_TO_MPS(wpt->speed); + break; + default: + wpt->speed = 0; + WAYPT_UNSET(wpt, speed); + warning(MYNAME ": Unknown GPSSpeedRef unit %c (0x%02x)!\n", speed_ref, speed_ref); + } + } + + if (lat_ref == 'S') wpt->latitude *= -1; + else if (lat_ref != 'N') warning(MYNAME ": GPSLatitudeRef not set! Using N(orth).\n"); + if (lon_ref == 'W') wpt->longitude *= -1; + else if (lon_ref != 'E') warning(MYNAME ": GPSLongitudeRef not set! Using E(east).\n"); + + if (datum != DATUM_WGS84) { + double alt; + GPS_Math_WGS84_To_Known_Datum_M(wpt->latitude, wpt->longitude, 0.0, + &wpt->latitude, &wpt->longitude, &alt, datum); + } + + if (mode == '2') { + wpt->fix = fix_2d; + if (gpsdop != unknown_alt) wpt->hdop = gpsdop; + } + else if (mode == '3') { + wpt->fix = fix_3d; + if (gpsdop != unknown_alt) wpt->pdop = gpsdop; + } + } + + return next_ifd; +} + +static void +exif_read(void) +{ + gbint32 code = 0; + + fileoffs = 0; + wpt = NULL; + + while (!gbfeof(fin)) { + + unsigned char c = (unsigned)gbfgetc(fin); + + code = (code << 8) | c; + if (code == 0x45786966) { /* Look for "Exif" */ + + gbsize_t next_ifd; + gbint32 ifd; + + int order = gbfgetint32(fin); + switch(order) { + case 0x49490000: /* "II" - Intel */ + byte_order = 'I'; + break; + case 0x4D4D0000: /* "MM" - Motorola */ + byte_order = 'M'; + break; + + default: + continue; + } + fin->big_endian = (byte_order == 'M'); + if (gbfgetint16(fin) != 0x002a) continue; + + fileoffs = gbftell(fin) - 4; + + next_ifd = gbfgetuint32(fin); + if (! next_ifd) continue; /* No IFD0 ? */ + + ifd = gps_ifd = exif_ifd = 0; + timestamp = UNKNOWN_TIMESTAMP; + + /* we need the wpt not only during GPS IFD */ + wpt = waypt_new(); + wpt->latitude = unknown_alt; + wpt->longitude = unknown_alt; + + while (next_ifd) { + gbfseek(fin, fileoffs + next_ifd, SEEK_SET); + next_ifd = exif_read_tags(ifd++); + } + if (exif_ifd) { + gbfseek(fin, fileoffs + exif_ifd, SEEK_SET); + (void) exif_read_tags(EXIF_IFD); + } + if (gps_ifd) { + gbfseek(fin, fileoffs + gps_ifd, SEEK_SET); + (void) exif_read_tags(GPS_IFD); + } + else { + warning(MYNAME ": No Exif-GPS information in file \"%s\"!\n", fin->name); + waypt_free(wpt); + wpt = NULL; + } + + if (! wpt) return; + + if (wpt->creation_time && (timestamp != UNKNOWN_TIMESTAMP)) { + struct tm tm; + tm = *gmtime(&wpt->creation_time); + tm.tm_hour = 0; + tm.tm_min = 0; + tm.tm_sec = 0; + wpt->creation_time = mkgmtime(&tm) + timestamp; + } + + if (opt_filename) { + char *c, *cx; + char *str = xstrdup(fin->name); + + cx = str; + if ((c = strrchr(cx, ':'))) cx = c + 1; + if ((c = strrchr(cx, '\\'))) cx = c + 1; + if ((c = strrchr(cx, '/'))) cx = c + 1; + if (((c = strchr(cx, '.'))) && (c != cx)) *c = '\0'; + + if (wpt->shortname) xfree(wpt->shortname); + wpt->shortname = xstrdup(cx); + xfree(str); + } + waypt_add(wpt); + + return; + } + } + warning(MYNAME ": No Exif header in file \"%s\"!\n", fin->name); +} + +#if 0 +static void +exif_wr_init(const char *fname) +{ + fout = gbfopen(fname, "w", MYNAME); +} + +static void +exif_wr_deinit(void) +{ + gbfclose(fout); +} + +static void +exif_write(void) +{ +} +#endif + +/**************************************************************************/ + +ff_vecs_t exif_vecs = { + ff_type_file, + { + ff_cap_read /* waypoints */, + ff_cap_none /* tracks */, + ff_cap_none /* routes */ + }, + exif_rd_init, + NULL, /* exif_wr_init, */ + exif_rd_deinit, + NULL, /* exif_wr_deinit, */ + exif_read, + NULL, /* exif_write */ + NULL, + exif_args, + CET_CHARSET_ASCII, 0 +}; + +/**************************************************************************/ diff --git a/filter_vecs.c b/filter_vecs.c index 75e4a5e1c..10d4670d9 100644 --- a/filter_vecs.c +++ b/filter_vecs.c @@ -1,7 +1,7 @@ /* Describe vectors containing filter operations. - Copyright (C) 2002,2004,2005,2006 Robert Lipe, robertlipe@usa.net + Copyright (C) 2002,2004,2005,2006,2007 Robert Lipe, robertlipe@usa.net This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,6 +22,7 @@ #include "defs.h" #include "filterdefs.h" #include "inifile.h" +#include "gbversion.h" typedef struct { filter_vecs_t *vec; @@ -267,14 +268,25 @@ alpha (const void *a, const void *b) return case_ignore_strcmp(ap->desc , bp->desc); } +static +void disp_help_url(const fl_vecs_t *vec, arglist_t *arg) +{ + printf("\t" WEB_DOC_DIR "/fmt_%s.html", vec->name); + if (arg) { + printf("#fmt_%s_o_%s",vec->name, arg->argstring); + } +} + static void disp_v1(const fl_vecs_t *vec) { arglist_t *ap; + disp_help_url(vec, NULL); + printf("\n"); for (ap = vec->vec->args; ap && ap->argstring; ap++) { - if ( !(ap->argtype & ARGTYPE_HIDDEN)) - printf("option\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", + if ( !(ap->argtype & ARGTYPE_HIDDEN)) { + printf("option\t%s\t%s\t%s\t%s\t%s\t%s\t%s", vec->name, ap->argstring, ap->helpstring, @@ -282,6 +294,9 @@ disp_v1(const fl_vecs_t *vec) ap->defaultvalue? ap->defaultvalue : "", ap->minvalue? ap->minvalue : "", ap->maxvalue? ap->maxvalue : ""); + disp_help_url(vec, ap); + printf("\n"); + } } } @@ -305,9 +320,12 @@ disp_filters(int version) case 0: case 1: for (vec = filter_vec_list; vec->vec; vec++) { - printf("%s\t%s\n", vec->name, vec->desc); - if (version > 0) + if (version == 0) { + printf("%s\t%s\n", vec->name, vec->desc); + } else { + printf("%s\t%s", vec->name, vec->desc); disp_v1(vec); + } } break; default: diff --git a/garmin.c b/garmin.c index c06f995dd..7ee0126cf 100644 --- a/garmin.c +++ b/garmin.c @@ -35,12 +35,16 @@ static GPS_PWay *tx_routelist; static GPS_PWay *cur_tx_routelist_entry; static GPS_PTrack *tx_tracklist; static GPS_PTrack *cur_tx_tracklist_entry; +static int my_track_count = 0; static char *getposn = NULL; static char *poweroff = NULL; +static char *resettime = NULL; static char *snlen = NULL; static char *snwhiteopt = NULL; static char *deficon = NULL; static char *category = NULL; +static char *categorybitsopt = NULL; +static int categorybits; #define MILITANT_VALID_WAYPT_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" @@ -58,8 +62,12 @@ arglist_t garmin_args[] = { NULL, ARGTYPE_BOOL, ARG_NOMINMAX}, { "power_off", &poweroff, "Command unit to power itself down", NULL, ARGTYPE_BOOL, ARG_NOMINMAX}, + { "resettime", &resettime, "Sync GPS time to computer time", + NULL, ARGTYPE_BOOL, ARG_NOMINMAX}, { "category", &category, "Category number to use for written waypoints", NULL, ARGTYPE_INT, "1", "16"}, + { "bitscategory", &categorybitsopt, "Bitmap of categories", + NULL, ARGTYPE_INT, "1", "65535"}, ARG_TERMINATOR }; @@ -90,6 +98,20 @@ rw_init(const char *fname) return; } + /* + * THis is Gross. The B&W Vista sometimes sets its time decades into + * the future with no way to reset it. This apparently can "cure" + * an affected unit. + */ + if (resettime) { + GPS_Command_Send_Time(fname, current_time()); + return; + } + + if (categorybitsopt) { + categorybits = strtol(categorybitsopt, NULL, 0); + } + if (GPS_Init(fname) < 0) { fatal(MYNAME ":Can't init %s\n", fname); } @@ -135,8 +157,8 @@ rw_init(const char *fname) case 130: /* Garmin Etrex (yellow) */ receiver_short_length = 6; break; - case 295: - /* eTrex (yellow, firmware v. 3.30) */ + case 295: /* eTrex (yellow, fw v. 3.30) */ + case 696: /* eTrex HC */ receiver_short_length = 6; valid_waypt_chars = MILITANT_VALID_WAYPT_CHARS " +-"; @@ -152,14 +174,22 @@ rw_init(const char *fname) receiver_short_length = 30; receiver_must_upper = 0; break; - case 292: /* (60|76)C[s]X series */ - case 421: /* Vista|Legend CX */ + case 292: /* (60|76)C[S]x series */ + case 421: /* Vista|Legend Cx */ + case 694: /* Legend HCx */ + case 695: /* Vista HCx */ + case 786: /* HC model */ receiver_short_length = 14; snwhiteopt = xstrdup("1"); receiver_must_upper = 0; /* This might be 8859-1 */ receiver_charset = CET_CHARSET_MS_ANSI; break; + case 291: /* GPSMAP 60CS, probably others */ + receiver_short_length = 10; + valid_waypt_chars = MILITANT_VALID_WAYPT_CHARS " +-"; + setshort_badchars(mkshort_handle, "\"$.,'!"); + break; case 231: /* Quest */ case 463: /* Quest 2 */ receiver_must_upper = 0; @@ -210,6 +240,8 @@ rw_init(const char *fname) if (receiver_charset) cet_convert_init(receiver_charset, 1); + + } static void @@ -236,13 +268,15 @@ static void waypt_read(void) { int i,n; - GPS_PWay *way; + GPS_PWay *way = NULL; if (getposn) { waypoint *wpt = waypt_new(); wpt->latitude = gps_save_lat; wpt->longitude = gps_save_lon; wpt->shortname = xstrdup("Position"); + if (gps_save_time) + wpt->creation_time = gps_save_time; waypt_add(wpt); return; } @@ -295,7 +329,9 @@ waypt_read(void) waypt_add(wpt_tmp); GPS_Way_Del(&way[i]); } - xfree(way); + if (way) { + xfree(way); + } } static @@ -729,16 +765,27 @@ waypoint_write(void) } way[i]->ident[sizeof(way[i]->ident)-1] = 0; - if (global_opts.smart_names && - wpt->gc_data.diff && wpt->gc_data.terr) { - snprintf(obuf, sizeof(obuf), "%s%d/%d %s", - get_gc_info(wpt), - wpt->gc_data.diff, wpt->gc_data.terr, - src); - memcpy(way[i]->cmnt, obuf, strlen(obuf)); - } else { - memcpy(way[i]->cmnt, src, strlen(src)); + // If we were explictly given a comment from GPX, use that. + if (wpt->description) { + memcpy(way[i]->cmnt, wpt->description, strlen(wpt->description)); + } else { + if (global_opts.smart_names && + wpt->gc_data.diff && wpt->gc_data.terr) { +#if 0 +xasprintf(&src, "%s %s", &wpt->shortname[2], src); +#endif + snprintf(obuf, sizeof(obuf), "%s%d/%d %s", + get_gc_info(wpt), + wpt->gc_data.diff, wpt->gc_data.terr, + src); + memcpy(way[i]->cmnt, obuf, strlen(obuf)); + } else { + memcpy(way[i]->cmnt, src, strlen(src)); + } } + + + way[i]->lon = wpt->longitude; way[i]->lat = wpt->latitude; @@ -772,6 +819,9 @@ waypoint_write(void) if (category) { way[i]->category = 1 << (atoi(category) - 1); } + if (categorybits) { + way[i]->category = categorybits; + } #if SOON garmin_fs_garmin_before_write(wpt, way[i], gps_waypt_type); #endif @@ -807,6 +857,7 @@ static void route_waypt_pr(const waypoint *wpt) { GPS_PWay rte = *cur_tx_routelist_entry; + char *s, *d; /* * As stupid as this is, libjeeps seems to want an empty @@ -830,7 +881,20 @@ route_waypt_pr(const waypoint *wpt) rte->alt_is_unknown = 1; rte->alt = 0; } - strncpy(rte->ident, wpt->shortname, sizeof(rte->ident)); + + // Garmin protocol spec says no spaces, no lowercase, etc. in a route. + // enforce that here, since jeeps doesn't. + // + // This was strncpy(rte->ident, wpt->shortname, sizeof(rte->ident)); + d = rte->ident; + for (s = wpt->shortname; *s; s++) { + int c = *s; + if (isalpha(c)) c = toupper(c); + if (strchr(MILITANT_VALID_WAYPT_CHARS, c)) { + *d++ = c; + } + } + rte->ident[sizeof(rte->ident)-1] = 0; if (wpt->description) { @@ -872,8 +936,11 @@ track_hdr_pr(const route_head *trk_head) if ( trk_head->rte_name ) { strncpy((*cur_tx_tracklist_entry)->trk_ident, trk_head->rte_name, sizeof((*cur_tx_tracklist_entry)->trk_ident)); (*cur_tx_tracklist_entry)->trk_ident[sizeof((*cur_tx_tracklist_entry)->trk_ident)-1] = 0; - } + } else { + sprintf((*cur_tx_tracklist_entry)->trk_ident, "TRACK%02d", my_track_count); + } cur_tx_tracklist_entry++; + my_track_count++; } static void @@ -901,7 +968,7 @@ track_write(void) for (i = 0; i < n; i++) { tx_tracklist[i] = GPS_Track_New(); } - + my_track_count = 0; track_disp_all(track_hdr_pr, route_noop, track_waypt_pr); GPS_Command_Send_Track(portname, tx_tracklist, n); diff --git a/garmin_fs.c b/garmin_fs.c index 3fa634eb4..76a65aa8d 100644 --- a/garmin_fs.c +++ b/garmin_fs.c @@ -2,7 +2,7 @@ Implementation of special data used by Garmin products. - Copyright (C) 2006 Olaf Klein, o.b.klein@gpsbabel.org + Copyright (C) 2006, 2007, 2008 Olaf Klein, o.b.klein@gpsbabel.org This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -133,6 +133,7 @@ garmin_fs_xml_fprint(gbfile *ofd, const waypoint *waypt) if (gmsd == NULL) return; + /* Find out if there is at least one field set */ addr = GMSD_GET(addr, ""); if (! *addr) addr = GMSD_GET(city, ""); if (! *addr) addr = GMSD_GET(country, ""); @@ -189,24 +190,42 @@ garmin_fs_xml_fprint(gbfile *ofd, const waypoint *waypt) gbfprintf(ofd, "%*s\n", --space * 2, ""); } if (*addr) { - char *str; + char *str, *tmp; gbfprintf(ofd, "%*s\n", space++ * 2, ""); - if ((str = GMSD_GET(addr, NULL))) - gbfprintf(ofd, "%*s%s\n", space * 2, "", str); - if ((str = GMSD_GET(city, NULL))) - gbfprintf(ofd, "%*s%s\n", space * 2, "", str); - if ((str = GMSD_GET(state, NULL))) - gbfprintf(ofd, "%*s%s\n", space * 2, "", str); - if ((str = GMSD_GET(country, NULL))) - gbfprintf(ofd, "%*s%s\n", space * 2, "", str); - if ((str = GMSD_GET(postal_code, NULL))) - gbfprintf(ofd, "%*s%s\n", space * 2, "", str); + if ((str = GMSD_GET(addr, NULL))) { + tmp = xml_entitize(str); + gbfprintf(ofd, "%*s%s\n", space * 2, "", tmp); + xfree(tmp); + } + if ((str = GMSD_GET(city, NULL))) { + tmp = xml_entitize(str); + gbfprintf(ofd, "%*s%s\n", space * 2, "", tmp); + xfree(tmp); + } + if ((str = GMSD_GET(state, NULL))) { + tmp = xml_entitize(str); + gbfprintf(ofd, "%*s%s\n", space * 2, "", tmp); + xfree(tmp); + } + if ((str = GMSD_GET(country, NULL))) { + tmp = xml_entitize(str); + gbfprintf(ofd, "%*s%s\n", space * 2, "", tmp); + xfree(tmp); + } + if ((str = GMSD_GET(postal_code, NULL))) { + tmp = xml_entitize(str); + gbfprintf(ofd, "%*s%s\n", space * 2, "", tmp); + xfree(tmp); + } gbfprintf(ofd, "%*s\n", --space * 2, ""); } + if (*phone) { - gbfprintf(ofd, "%*s%s\n", space * 2, "", phone); + char *tmp = xml_entitize(phone); + gbfprintf(ofd, "%*s%s\n", space * 2, "", tmp); + xfree(tmp); } gbfprintf(ofd, "%*s\n", --space * 2, ""); diff --git a/garmin_gpi.c b/garmin_gpi.c index 26536684e..e2b9ec07f 100644 --- a/garmin_gpi.c +++ b/garmin_gpi.c @@ -32,11 +32,14 @@ avoid endless loop in group splitting * 2007/07/10: put address fields (i.e. city) into GMSD * 2007/07/12: add write support for new address fields + * 2007/10/20: add option unique + * 2007/12/02: support speed and proximity distance (+ alerts) + * 2008/01/14: fix structure error after adding speed/proximity + * 2008/03/22: add options "speed" and "proximity" (default values) and "sleep" ToDo: * Display mode ("Symbol & Name") ??? not in gpi ??? - * decode speed/proximity * support category from GMSD "Garmin Special Data" */ @@ -66,8 +69,13 @@ #define GPI_ADDR_ADDR 16 static char *opt_cat, *opt_pos, *opt_notes, *opt_hide_bitmap, *opt_descr, *opt_bitmap; +static char *opt_unique, *opt_alerts, *opt_units, *opt_speed, *opt_proximity, *opt_sleep; +static double defspeed, defproximity; +static int alerts; static arglist_t garmin_gpi_args[] = { + {"alerts", &opt_alerts, "Enable alerts on speed or proximity distance", + NULL, ARGTYPE_BOOL, ARG_NOMINMAX}, {"bitmap", &opt_bitmap, "Use specified bitmap on output", NULL, ARGTYPE_FILE, ARG_NOMINMAX}, {"category", &opt_cat, "Default category on output", @@ -80,6 +88,16 @@ static arglist_t garmin_gpi_args[] = { NULL, ARGTYPE_BOOL, ARG_NOMINMAX}, {"position", &opt_pos, "Write position to address field", NULL, ARGTYPE_BOOL, ARG_NOMINMAX}, + {"proximity", &opt_proximity, "Default proximity", + NULL, ARGTYPE_FLOAT, ARG_NOMINMAX}, + {"sleep", &opt_sleep, "After output job done sleep n second(s)", + NULL, ARGTYPE_INT, "1", NULL}, + {"speed", &opt_speed, "Default speed", + NULL, ARGTYPE_FLOAT, ARG_NOMINMAX}, + {"unique", &opt_unique, "Create unique waypoint names (default = yes)", + "Y", ARGTYPE_BOOL, ARG_NOMINMAX}, + {"units", &opt_units, "Units used for names with @speed ('s'tatute or 'm'etric)", + "m", ARGTYPE_STRING, ARG_NOMINMAX}, ARG_TERMINATOR }; @@ -97,6 +115,7 @@ typedef struct writer_data_s { queue Q; int ct; int sz; + int alert; bounds bds; struct writer_data_s *top_left; struct writer_data_s *top_right; @@ -145,6 +164,7 @@ typedef struct { typedef struct { int sz; + int alerts; short mask; char addr_is_dynamic; char *addr; @@ -160,6 +180,8 @@ static gbint32 codepage; /* code-page, i.e. 1252 */ static reader_data_t *rdata; static writer_data_t *wdata; static short_handle short_h; +static char units; +static time_t gpi_timestamp = 0; #ifdef GPI_DBG # define PP warning("@%1$6x (%1$8d): ", gbftell(fin)) @@ -411,7 +433,8 @@ read_poi_group(const int sz, const int tag) static int read_tag(const char *caller, const int tag, waypoint *wpt) { - int pos, sz; + int pos, sz, dist; + double speed; short mask; char *str; garmin_fs_t *gmsd; @@ -426,7 +449,29 @@ read_tag(const char *caller, const int tag, waypoint *wpt) if ((tag >= 0x80000) && (tag <= 0x800ff)) sz += 4; switch(tag) { - case 0x3: /* size = 12 ? sound */ + case 0x3: /* size = 12 */ + + dist = gbfgetint16(fin); /* proximity distance in meters */ + speed = (double)gbfgetint16(fin) / 100; /* speed in meters per second */ + + if (dist > 0) WAYPT_SET(wpt, proximity, dist); + if (speed > 0) { + /* speed isn't part of a normal waypoint + WAYPT_SET(wpt, speed, speed); + */ + if ((wpt->shortname == NULL) || (! strchr(wpt->shortname, '@'))) { + if (units == 's') speed = MPS_TO_MPH(speed); + else speed = MPS_TO_KPH(speed); + xasprintf(&str, "%s@%.f", wpt->shortname ? wpt->shortname : "WPT", speed); + if (wpt->shortname) xfree(wpt->shortname); + wpt->shortname = str; + } + } + + (void) gbfgetint32(fin); + (void) gbfgetint32(fin); + break; + case 0x4: /* size = 2 ? */ case 0x6: /* size = 2 ? */ break; @@ -687,8 +732,38 @@ wdata_compute_size(writer_data_t *data) res += 12; /* tag/sz/sub-sz */ res += 19; /* poi fixed size */ res += strlen(wpt->shortname); - res += 10; /* tag(4) */ + if (! opt_hide_bitmap) res += 10; /* tag(4) */ + + dt = xcalloc(1, sizeof(*dt)); + wpt->extra_data = dt; + if (alerts) { + char *pos; + + if ((pos = strchr(wpt->shortname, '@'))) { + double speed, scale; + if (units == 's') scale = MPH_TO_MPS(1); + else scale = KPH_TO_MPS(1); + parse_speed(pos + 1, &speed, scale, MYNAME); + if (speed > 0) WAYPT_SET(wpt, speed, speed); +#if 0 + if (pos > wpt->shortname) wpt->shortname[pos - wpt->shortname] = '\0'; +#endif + } + else if ((opt_speed) && (! WAYPT_HAS(wpt, speed))) + WAYPT_SET(wpt, speed, defspeed); + + if ((opt_proximity) && (! WAYPT_HAS(wpt, proximity))) + WAYPT_SET(wpt, proximity, defproximity); + + if ((WAYPT_HAS(wpt, speed) && (wpt->speed > 0)) || + (WAYPT_HAS(wpt, proximity) && (wpt->proximity > 0))) { + data->alert = 1; + dt->alerts++; + res += 20; /* tag(3) */ + } + } + str = NULL; if (opt_descr) { if (wpt->description && *wpt->description) @@ -701,8 +776,6 @@ wdata_compute_size(writer_data_t *data) else if (opt_pos) str = pretty_deg_format(wpt->latitude, wpt->longitude, 's', " ", 0); - dt = xcalloc(1, sizeof(*dt)); - wpt->extra_data = dt; if (str) { dt->addr_is_dynamic = 1; @@ -741,6 +814,7 @@ wdata_compute_size(writer_data_t *data) str = wpt->description; if (! str) str = wpt->notes; +// if (str && (strcmp(str, wpt->shortname) == 0)) str = NULL; if (str) res += (12 + 4 + strlen(str)); } @@ -769,11 +843,9 @@ wdata_write(const writer_data_t *data) gbfputint32(GPS_Math_Deg_To_Semi(data->bds.min_lat), fout); gbfputint32(GPS_Math_Deg_To_Semi(data->bds.min_lon), fout); - gbfputc(0, fout); /* three unknown bytes */ - gbfputc(0, fout); /* ? should be zero ? */ - gbfputc(0, fout); - - gbfputint32(0x1000100, fout); /* ? const 0x1000100 ? */ + gbfputint32(0, fout); + gbfputint16(1, fout); + gbfputc(data->alert, fout); QUEUE_FOR_EACH(&data->Q, elem, tmp) { char *str; @@ -783,14 +855,16 @@ wdata_write(const writer_data_t *data) str = wpt->description; if (! str) str = wpt->notes; +// if (str && (strcmp(str, wpt->shortname) == 0)) str = NULL; gbfputint32(0x80002, fout); s0 = s1 = 19 + strlen(wpt->shortname); - s0 += 10; /* tag(4) */ + if (! opt_hide_bitmap) s0 += 10; /* tag(4) */ if (str) s0 += (12 + 4 + strlen(str)); /* descr */ if (dt->sz) s0 += (12 + dt->sz); /* address part */ if (dt->phone_nr) s0 += (12 + 4 + strlen(dt->phone_nr)); + if (dt->alerts) s0 += 20; /* tag(3) */ gbfputint32(s0, fout); /* size of following data (tag) */ gbfputint32(s1, fout); /* basic size (without options) */ @@ -802,11 +876,38 @@ wdata_write(const writer_data_t *data) gbfputc(0, fout); /* seems to be 1 when extra options present */ write_string(wpt->shortname, 1); - - gbfputint32(4, fout); /* tag(4) */ - gbfputint32(2, fout); /* ? always 2 == version ??? */ - if (opt_hide_bitmap) gbfputint16(0x3ff, fout); /* values != 0 hides the bitmap */ - else gbfputint16(0, fout); + + if (dt->alerts) { + char flag = 0; + + gbfputint32(3, fout); /* tag(3) */ + gbfputint32(12, fout); /* always 12 */ + + if (WAYPT_HAS(wpt, proximity) && (wpt->proximity > 0)) { + gbfputint16((int) wpt->proximity, fout); + flag = 4; + } + else + gbfputint16(0, fout); + if (WAYPT_HAS(wpt, speed) && (wpt->speed > 0)) { + gbfputint16((int) (wpt->speed * 100), fout); + flag = 5; + } + else + gbfputint16(0, fout); + + gbfputint32(0x100100, fout); /* ??? */ + gbfputc(1, fout); /* ??? */ + gbfputc(1, fout); /* ??? */ + gbfputc(flag, fout); + gbfputc(0x10, fout); /* ??? */ + } + + if (! opt_hide_bitmap) { + gbfputint32(4, fout); /* tag(4) */ + gbfputint32(2, fout); /* ? always 2 == version ??? */ + gbfputint16(0, fout); + } if (str) { gbfputint32(0xa, fout); @@ -872,10 +973,11 @@ write_category(const char *category, const char *image, const int image_sz) static void write_header(void) { - time_t time = gpsbabel_time; /* !!! ZERO during leaktest !!! */ + time_t time = gpi_timestamp; if (time != 0) { - struct tm tm = *gmtime(&time); + struct tm tm; + tm = *gmtime(&time); tm.tm_year -= 20; time = mkgmtime(&tm); time += SECONDS_PER_DAY; @@ -919,9 +1021,11 @@ enum_waypt_cb(const waypoint *ref) wpt = waypt_dupe(ref); - str = mkshort(short_h, wpt->shortname); - xfree(wpt->shortname); - wpt->shortname = str; + if (*opt_unique == '1') { + str = mkshort(short_h, wpt->shortname); + xfree(wpt->shortname); + wpt->shortname = str; + } wdata_add_wpt(wdata, wpt); } @@ -959,6 +1063,10 @@ load_bitmap_from_file(const char *fname, char **data, int *data_sz) src_h.used_colors = gbfgetint32(f); src_h.important_colors = gbfgetint32(f); + /* Workaround for indexed BMP's with used_colors = 0 */ + if ((src_h.bpp == 8) && (src_h.used_colors == 0)) + src_h.used_colors = (src_h.image_offset - gbftell(f)) / 4; + #ifdef GPI_DBG printf("data size: 0x%1$x (%1$d)\n", src_h.size); printf("image data offset: 0x%1$x (%1$d)\n", src_h.image_offset); @@ -974,6 +1082,7 @@ load_bitmap_from_file(const char *fname, char **data, int *data_sz) printf("number of colors: 0x%1$x (%1$d)\n", src_h.used_colors); printf("important colors: 0x%1$x (%1$d)\n", src_h.important_colors); #endif + /* sort out unsupported files */ if (! ((src_h.width <= 24) && (src_h.height <= 24) && (src_h.width > 0) && (src_h.height > 0))) @@ -1082,6 +1191,10 @@ garmin_gpi_rd_init(const char *fname) cet_convert_init(cp, 1); } else warning(MYNAME ": Unsupported code page (%d).\n", codepage); + + units = tolower(opt_units[0]); + if ((units != 'm') && (units != 's')) + fatal(MYNAME ": Unknown units parameter (%c).\n", opt_units[0]); } @@ -1092,6 +1205,16 @@ garmin_gpi_wr_init(const char *fname) cet_cs_vec_t *vec; int i; + if (gpi_timestamp != 0) { /* not the first gpi output session */ + time_t t = time(NULL); + if (t <= gpi_timestamp) + gpi_timestamp++; /* don't create files with same timestamp */ + else + gpi_timestamp = t; + } + else + gpi_timestamp = gpsbabel_time; /* always ZERO during 'testo' */ + fout = gbfopen_le(fname, "wb", MYNAME); short_h = mkshort_new_handle(); @@ -1120,6 +1243,27 @@ garmin_gpi_wr_init(const char *fname) fatal(MYNAME ": Valid values are CP1250 to CP1257.\n"); } + units = tolower(opt_units[0]); + if ((units != 'm') && (units != 's')) + fatal(MYNAME ": Unknown units parameter (%c).\n", opt_units[0]); + + alerts = (opt_alerts) ? 1 : 0; + + if (opt_speed) { + double scale; + alerts = 1; /* Force alerts to be enabled */ + if (units == 's') scale = MPH_TO_MPS(1); /* We need speed in meters per second */ + else scale = KPH_TO_MPS(1); + parse_speed(opt_speed, &defspeed, scale, MYNAME); + } + + if (opt_proximity) { + double scale; + alerts = 1; /* Force alerts to be enabled */ + if (units == 's') scale = MILES_TO_METERS(1); /* We need proximity in meters */ + else scale = 1000.0; /* one kilometer in meters */ + parse_distance(opt_proximity, &defproximity, scale, MYNAME); + } wdata = wdata_alloc(); } @@ -1140,6 +1284,15 @@ garmin_gpi_wr_deinit(void) wdata_free(wdata); mkshort_del_handle(&short_h); gbfclose(fout); + + if ((opt_sleep) && (gpi_timestamp != 0)) { /* don't sleep during 'testo' */ + int sleep = atoi(opt_sleep); + if (sleep < 1) sleep = 1; + gpi_timestamp += sleep; + while (gpi_timestamp > time(NULL)) { + gb_sleep(100); + } + } } diff --git a/garmin_tables.c b/garmin_tables.c index 3bae4469c..11a064ad0 100644 --- a/garmin_tables.c +++ b/garmin_tables.c @@ -184,7 +184,7 @@ icon_mapping_t garmin_icon_table[] = { * .... * { -2, 8192, "Custom 511" }, */ -#if 0 +#if 1 /* Since Garmin is busily adding icons to new units, we have to hide * these so we can pass them through to the new entries. 6/2/07 robertl */ @@ -617,6 +617,7 @@ grid_mapping_t gt_mps_grid_names[] = { "dms", "Lat/Lon hddd*mm'ss.s\"", grid_lat_lon_dms }, { "bng", "British National Grid", grid_bng }, { "utm", "UTM", grid_utm }, + { "swiss", "Swiss grid", grid_swiss }, { NULL, NULL, 0 } }; diff --git a/garmin_txt.c b/garmin_txt.c index 97f7716c9..e17a9a6fc 100644 --- a/garmin_txt.c +++ b/garmin_txt.c @@ -73,7 +73,7 @@ typedef enum { unknown_header } header_type; -#define MAX_HEADER_FIELDS 24 +#define MAX_HEADER_FIELDS 36 static char *header_lines[unknown_header + 1][MAX_HEADER_FIELDS]; static int header_fields[unknown_header + 1][MAX_HEADER_FIELDS]; @@ -133,7 +133,7 @@ static char *headers[] = { "Display Mode\tColor\tSymbol\tFacility\tCity\tState\tCountry\t" "Date Modified\tLink\tCategories", "Waypoint Name\tDistance\tLeg Length\tCourse", - "Position\tTime\tAltitude\tDepth\tLeg Length\tLeg Time\tLeg Speed\tLeg Course", + "Position\tTime\tAltitude\tDepth\tTemperature\tLeg Length\tLeg Time\tLeg Speed\tLeg Course", "Name\tLength\tCourse\tWaypoints\tLink", "Name\tStart Time\tElapsed Time\tLength\tAverage Speed\tLink", NULL @@ -164,67 +164,17 @@ init_date_and_time_format(void) xfree(c); } -static double -distance(double lat1, double lon1, double lat2, double lon2) -{ - double res = radtometers(gcdist(RAD(lat1), RAD(lon1), RAD(lat2), RAD(lon2))); - if (res < 0.1) res = 0; /* calc. diffs on 32- and 64-bit hosts */ - return res; -} - -static double -course_deg(double lat1, double lon1, double lat2, double lon2) -{ - return DEG(heading(RAD(lat1), RAD(lon1), RAD(lat2), RAD(lon2))); -} - -static double -waypt_distance(const waypoint *A, const waypoint *B) /* !!! from A to B !!! */ -{ - double dist = 0; - garmin_fs_p gmsd; - - if ((A == NULL) || (B == NULL)) return 0; - - gmsd = GMSD_FIND(A); - if ((gmsd != NULL) && (gmsd->ilinks != NULL)) - { - garmin_ilink_t *link = gmsd->ilinks; - - dist = distance(A->latitude, A->longitude, link->lat, link->lon); - while (link->next != NULL) - { - garmin_ilink_t *prev = link; - link = link->next; - dist += distance(prev->lat, prev->lon, link->lat, link->lon); - } - dist += distance(link->lat, link->lon, B->latitude, B->longitude); - } else - { - dist = distance(A->latitude, A->longitude, B->latitude, B->longitude); - } - return dist; -} - static void -convert_datum(waypoint *wpt, const int to_internal_wgs84, double *dest_lat, double *dest_lon) +convert_datum(const waypoint *wpt, double *dest_lat, double *dest_lon) { double alt; if (datum_index == DATUM_WGS84 ) { - if (to_internal_wgs84 == 0) { - *dest_lat = wpt->latitude; - *dest_lon = wpt->longitude; - } - return; + *dest_lat = wpt->latitude; + *dest_lon = wpt->longitude; } - - if (to_internal_wgs84) { /* convert the waypoint himself */ - GPS_Math_Known_Datum_To_WGS84_M(wpt->latitude, wpt->longitude, 0.0, - &wpt->latitude, &wpt->longitude, &alt, datum_index); - } else - GPS_Math_WGS84_To_Known_Datum_M(wpt->latitude, wpt->longitude, 0.0, - dest_lat, dest_lon, &alt, datum_index); + else GPS_Math_WGS84_To_Known_Datum_M(wpt->latitude, wpt->longitude, 0.0, + dest_lat, dest_lon, &alt, datum_index); } /* WRITER *****************************************************************/ @@ -298,7 +248,7 @@ prework_wpt_cb(const waypoint *wpt) if (prev != NULL) { cur_info->time += (wpt->creation_time - prev->creation_time); - cur_info->length += waypt_distance(prev, wpt); + cur_info->length += waypt_distance_ex(prev, wpt); } else { cur_info->first_wpt = (waypoint *)wpt; @@ -315,14 +265,14 @@ prework_wpt_cb(const waypoint *wpt) static void print_position(const waypoint *wpt) { - int valid; + int valid = 1; double lat, lon, north, east; char latsig, lonsig; double latmin, lonmin, latsec, lonsec; int latint, lonint, zone; char map[3], zonec; - convert_datum((waypoint *)wpt, 0, &lat, &lon); + convert_datum(wpt, &lat, &lon); /* ----------------------------------------------------------------------------*/ /* the following code is from pretty_deg_format (util.c) */ @@ -365,20 +315,33 @@ print_position(const waypoint *wpt) case grid_bng: valid = GPS_Math_WGS84_To_UKOSMap_M(wpt->latitude, wpt->longitude, &east, &north, map); - is_fatal(! valid, MYNAME ": Some (or all?) of the coordinates cannot be displayed using \"BNG\"."); - gbfprintf(fout, "%s %5.0f %5.0f\t", map, east, north); + if (valid) gbfprintf(fout, "%s %5.0f %5.0f\t", map, east, north); break; case grid_utm: valid = GPS_Math_Known_Datum_To_UTM_EN(lat, lon, &east, &north, &zone, &zonec, datum_index); - gbfprintf(fout, "%02d %c %.0f %.0f\t", zone, zonec, east, north); + if (valid) gbfprintf(fout, "%02d %c %.0f %.0f\t", zone, zonec, east, north); + break; + + case grid_swiss: + + valid = GPS_Math_WGS84_To_CH1903_NGEN(wpt->latitude, wpt->longitude, &east, &north); + if (valid) gbfprintf(fout, "%.f %.f\t", east, north); break; default: fatal("ToDo\n"); } + + if (! valid) { + gbfprintf(fout, "#####\n"); + fatal(MYNAME ": %s (%s) is outside of convertable area \"%s\"!\n", + wpt->shortname ? wpt->shortname : "Waypoint", + pretty_deg_format(wpt->latitude, wpt->longitude, 'd', NULL, 0), + gt_get_mps_grid_longname(grid_index, MYNAME)); + } } static void @@ -387,6 +350,10 @@ print_date_and_time(const time_t time, const int time_only) struct tm tm; char tbuf[32]; + if (time < 0) { + gbfprintf(fout, "\t"); + return; + } if (time_only) { tm = *gmtime(&time); snprintf(tbuf, sizeof(tbuf), "%d:%02d:%02d", tm.tm_hour, tm.tm_min, tm.tm_sec); @@ -440,16 +407,13 @@ print_course(const waypoint *A, const waypoint *B) /* seems to be okay */ { if ((A != NULL) && (B != NULL) && (A != B)) { int course; - course = si_round((double)360 - course_deg(A->latitude, A->longitude, B->latitude, B->longitude)); - if (course >= 360) { - course -= 360; - } + course = si_round(waypt_course(A, B)); cet_gbfprintf(fout, &cet_cs_vec_cp1252, "%d%c true", course, 0xB0); } } static void -print_distance(const double distance, const int no_scale, const int with_tab) +print_distance(const double distance, const int no_scale, const int with_tab, const int decis) { double dist = distance; @@ -457,7 +421,7 @@ print_distance(const double distance, const int no_scale, const int with_tab) dist = METERS_TO_FEET(dist); if ((dist < 5280) || no_scale) - gbfprintf(fout, "%.f ft", dist); + gbfprintf(fout, "%.*f ft", decis, dist); else { dist = METERS_TO_MILES(distance); if (dist < (double)100) @@ -469,7 +433,7 @@ print_distance(const double distance, const int no_scale, const int with_tab) else { if ((dist < 1000) || no_scale) - gbfprintf(fout, "%.f m", dist); + gbfprintf(fout, "%.*f m", decis, dist); else { dist = dist / (double)1000.0; if (dist < (double)100) @@ -511,6 +475,15 @@ print_speed(double *distance, time_t *time) gbfprintf(fout, "\t"); } +static void +print_temperature(const float temperature) +{ + if (gtxt_flags.celsius) + gbfprintf(fout, "%.f C", temperature); + else + gbfprintf(fout, "%.f F", (temperature * 1.8) + 32); +} + static void print_string(const char *fmt, const char *string) { @@ -573,26 +546,22 @@ write_waypt(const waypoint *wpt) print_position(wpt); if IS_VALID_ALT(wpt->altitude) - print_distance(wpt->altitude, 1, 0); + print_distance(wpt->altitude, 1, 0, 0); gbfprintf(fout, "\t"); x = WAYPT_GET(wpt, depth, unknown_alt); if (x != unknown_alt) - print_distance(x, 1, 0); + print_distance(x, 1, 0, 1); gbfprintf(fout, "\t"); x = WAYPT_GET(wpt, proximity, unknown_alt); if (x != unknown_alt) - print_distance(x, 0, 0); + print_distance(x, 0, 0, 0); gbfprintf(fout, "\t"); - x = WAYPT_GET(wpt, temperature, unknown_alt); - if (x != unknown_alt) { - if (gtxt_flags.celsius) - gbfprintf(fout, "%.f C", x); - else - gbfprintf(fout, "%.f F", (x * 1.8) + 32); - } + x = WAYPT_GET(wpt, temperature, -999); + if (x != -999) + print_temperature(x); gbfprintf(fout, "\t%s\t", dspl_mode); gbfprintf(fout, "Unknown\t"); /* Color is fixed: Unknown */ @@ -632,7 +601,7 @@ route_disp_hdr_cb(const route_head *rte) } print_string("\r\nRoute\t%s\t", current_trk->rte_name ? current_trk->rte_name : ""); - print_distance(cur_info->length, 0, 1); + print_distance(cur_info->length, 0, 1, 0); print_course(cur_info->first_wpt, cur_info->last_wpt); gbfprintf(fout, "\t%d waypoints\t", cur_info->count); print_string("%s\r\n", rte->rte_url ? rte->rte_url : ""); @@ -655,14 +624,14 @@ route_disp_wpt_cb(const waypoint *wpt) if (prev != NULL) { - double dist = waypt_distance(prev, wpt); + double dist = waypt_distance_ex(prev, wpt); cur_info->total += dist; - print_distance(cur_info->total, 0, 1); - print_distance(dist, 0, 1); + print_distance(cur_info->total, 0, 1, 0); + print_distance(dist, 0, 1, 0); print_course(prev, wpt); } else - print_distance(0, 1, 0); + print_distance(0, 1, 0, 0); gbfprintf(fout, "\r\n"); @@ -686,7 +655,7 @@ track_disp_hdr_cb(const route_head *track) print_string("\r\nTrack\t%s\t", current_trk->rte_name ? current_trk->rte_name : ""); print_date_and_time(cur_info->start, 0); print_date_and_time(cur_info->time, 1); - print_distance(cur_info->length, 0, 1); + print_distance(cur_info->length, 0, 1, 0); print_speed(&cur_info->length, &cur_info->time); print_string("%s", (track->rte_url != NULL) ? track->rte_url : ""); gbfprintf(fout, "\r\n\r\nHeader\t%s\r\n\r\n", headers[trkpt_header]); @@ -703,20 +672,30 @@ track_disp_wpt_cb(const waypoint *wpt) { waypoint *prev = cur_info->prev_wpt; time_t delta; - double dist; + double dist, depth; gbfprintf(fout, "Trackpoint\t"); print_position(wpt); print_date_and_time(wpt->creation_time, 0); if IS_VALID_ALT(wpt->altitude) - print_distance(wpt->altitude, 1, 0); - gbfprintf(fout, "\t0.0 %s", (gtxt_flags.metric) ? "m" : "ft"); + print_distance(wpt->altitude, 1, 0, 0); + + gbfprintf(fout, "\t"); + depth = WAYPT_GET(wpt, depth, unknown_alt); + if (depth != unknown_alt) + print_distance(depth, 1, 0, 1); + if (prev != NULL) { + float temp; gbfprintf(fout, "\t"); delta = wpt->creation_time - prev->creation_time; - dist = distance(prev->latitude, prev->longitude, wpt->latitude, wpt->longitude); - print_distance(dist, 0, 1); + temp = WAYPT_GET(wpt, temperature, -999); + if (temp != -999) + print_temperature(temp); + gbfprintf(fout, "\t"); + dist = waypt_distance_ex(prev, wpt); + print_distance(dist, 0, 1, 0); print_date_and_time(delta, 1); print_speed(&dist, &delta); print_course(prev, wpt); @@ -767,6 +746,9 @@ garmin_txt_wr_init(const char *fname) case grid_bng: /* force datum to "Ord Srvy Grt Britn" */ datum_index = DATUM_OSGB36; break; + case grid_swiss: /* force datum to "Ord Srvy Grt Britn" */ + datum_index = DATUM_WGS84; + break; default: datum_index = gt_lookup_datum_index(datum_str, MYNAME); } @@ -870,51 +852,6 @@ free_header(const header_type ht) /* data parsers */ -#if 0 -/* moved to util.c */ -static void -parse_position(const char *str, waypoint *wpt) -{ -...... -} -#endif - -static int -parse_distance(const char *str, double *value) -{ - double x; - char *buff; - - if ((str == NULL) || (*str == '\0')) return 0; - - buff = xmalloc(strlen(str) + 1); - sscanf(str, "%lf %s", &x, buff); - - if (case_ignore_strcmp(buff, "km") == 0) { - *value = x * (double)1000; - } - else if (case_ignore_strcmp(buff, "m") == 0) { /* meters */ - *value = x; - } - else if (case_ignore_strcmp(buff, "ft") == 0) { /* feet */ - *value = FEET_TO_METERS(x); - } - else if (case_ignore_strcmp(buff, "nm") == 0) { /* mile (nautical / geographical) */ - *value = NMILES_TO_METERS(x); - } - else if (case_ignore_strcmp(buff, "mi") == 0) { /* mile (statute) */ - *value = MILES_TO_METERS(x); - } - else if (case_ignore_strcmp(buff, "fa") == 0) { /* fathom */ - *value = FATHOMS_TO_METERS(x); - } - else - fatal(MYNAME ": Unknown distance unit \"%s\" at line %d!\n", str, current_line); - - xfree(buff); - return 1; -} - static int parse_date_and_time(char *str, time_t *value) { @@ -1051,7 +988,7 @@ bind_fields(const header_type ht) c = fields; field_no = 1; - while (c != NULL) { + while (*c) { if (strcmp(c, name) == 0) { header_fields[ht][i] = field_no; #if 0 @@ -1128,9 +1065,9 @@ parse_waypoint(void) parse_coordinates(str, datum_index, grid_index, &wpt->latitude, &wpt->longitude, MYNAME); break; - case 5: if (parse_distance(str, &d)) wpt->altitude = d; break; - case 6: if (parse_distance(str, &d)) WAYPT_SET(wpt, depth, d); break; - case 7: if (parse_distance(str, &d)) WAYPT_SET(wpt, proximity, d); break; + case 5: if (parse_distance(str, &d, 1, MYNAME)) wpt->altitude = d; break; + case 6: if (parse_distance(str, &d, 1, MYNAME)) WAYPT_SET(wpt, depth, d); break; + case 7: if (parse_distance(str, &d, 1, MYNAME)) WAYPT_SET(wpt, proximity, d); break; case 8: if (parse_temperature(str, &d)) WAYPT_SET(wpt, temperature, d); break; case 9: if (parse_display(str, &i)) GMSD_SET(display, i); break; case 10: break; /* skip color */ @@ -1232,16 +1169,39 @@ parse_track_waypoint(void) wpt = waypt_new(); while ((str = csv_lineparse(NULL, "\t", "", column++))) { - int field_no = header_fields[trkpt_header][column]; + int field_no; + double x; + + if (! *str) continue; + + field_no = header_fields[trkpt_header][column]; switch(field_no) { - case 1: parse_coordinates(str, datum_index, grid_index, + case 1: + parse_coordinates(str, datum_index, grid_index, &wpt->latitude, &wpt->longitude, MYNAME); break; - case 2: parse_date_and_time(str, &wpt->creation_time); break; - case 3: parse_distance(str, &wpt->altitude); break; + case 2: + parse_date_and_time(str, &wpt->creation_time); + break; + case 3: + if (parse_distance(str, &x, 1, MYNAME)) + wpt->altitude = x; + break; + case 4: + if (parse_distance(str, &x, 1, MYNAME)) WAYPT_SET(wpt, depth, x); + break; + case 5: + if (parse_temperature(str, &x)) WAYPT_SET(wpt, temperature, x); + break; + case 8: + if (parse_speed(str, &x, 1, MYNAME)) WAYPT_SET(wpt, speed, x); + break; + case 9: + WAYPT_SET(wpt, course, atoi(str)); + break; } } - route_add_wpt(current_trk, wpt); + track_add_wpt(current_trk, wpt); } /***************************************************************/ @@ -1285,11 +1245,12 @@ garmin_txt_read(void) current_line++; cin = lrtrim(buff); if (*cin == '\0') continue; - + cin = csv_lineparse(cin, "\t", "", 0); if (cin == NULL) continue; - else if (case_ignore_strcmp(cin, "Header") == 0) parse_header(); + + if (case_ignore_strcmp(cin, "Header") == 0) parse_header(); else if (case_ignore_strcmp(cin, "Grid") == 0) parse_grid(); else if (case_ignore_strcmp(cin, "Datum") == 0) parse_datum(); else if (case_ignore_strcmp(cin, "Waypoint") == 0) parse_waypoint(); diff --git a/gbfile.c b/gbfile.c index 3b3489e2a..6bb978599 100644 --- a/gbfile.c +++ b/gbfile.c @@ -289,18 +289,17 @@ gbfread(void *buf, const gbsize_t size, const gbsize_t members, gbfile *file) } /* - * gbfprintf: (as fprintf) + * gbvfprintf: (as vfprintf) */ -int -gbfprintf(gbfile *file, const char *format, ...) +int gbvfprintf(gbfile *file, const char *format, va_list ap) { int len; for (;;) { va_list args; - va_start(args, format); + va_copy(args, ap); len = vsnprintf(file->buff, file->buffsz, format, args); va_end(args); @@ -329,6 +328,23 @@ gbfprintf(gbfile *file, const char *format, ...) return gbfwrite(file->buff, 1, len, file); } +/* + * gbfprintf: (as fprintf) + */ + +int +gbfprintf(gbfile *file, const char *format, ...) +{ + va_list args; + int result; + + va_start(args, format); + result = gbvfprintf(file, format, args); + va_end(args); + + return result; +} + /* * gbfputc: (as fputc) */ @@ -377,9 +393,9 @@ gbfwrite(const void *buf, const gbsize_t size, const gbsize_t members, gbfile *f } if (result != members) { - fatal("%s: Could not write %u bytes to %s!\n", + fatal("%s: Could not write %lld bytes to %s!\n", file->module, - (members - result) * size, + (long long int) (members - result) * size, file->name); } @@ -455,7 +471,7 @@ gbferror(gbfile *file) void gbfrewind(gbfile *file) { - (void)gbfseek(file, 0, SEEK_SET); + (void) gbfseek(file, 0, SEEK_SET); gbfclearerr(file); } @@ -466,9 +482,9 @@ gbfrewind(gbfile *file) int gbfseek(gbfile *file, gbint32 offset, int whence) { + int result; if (file->gzapi) { - int result; assert(whence != SEEK_END); @@ -485,10 +501,26 @@ gbfseek(gbfile *file, gbint32 offset, int whence) fatal("%s: online compression not yet supported for this format!", file->module); } return 0; - } else { - return fseek(file->handle.std, offset, whence); + gbsize_t pos = 0; + + if (whence != SEEK_SET) pos = ftell(file->handle.std); + + result = fseek(file->handle.std, offset, whence); + if (result != 0) { + switch (whence) { + case SEEK_CUR: + case SEEK_END: pos = pos + offset; break; + case SEEK_SET: pos = offset; break; + default: + fatal("%s: Unknown seek operation (%d) for file %s!\n", + file->module, whence, file->name); + } + fatal("%s: Unable to set file (%s) to position (%llu)!\n", + file->module, file->name, (long long unsigned) pos); + } + return 0; } } @@ -499,22 +531,27 @@ gbfseek(gbfile *file, gbint32 offset, int whence) gbsize_t gbftell(gbfile *file) { + gbsize_t result; + if (file->gzapi) { #if !ZLIB_INHIBITED - gbsize_t result = gztell(file->handle.gz); + result = gztell(file->handle.gz); if (file->back != -1) { // file->back = -1; result--; } - return result; #else fatal(NO_ZLIB); - return -1; + result = -1; #endif } else { - return ftell(file->handle.std); + result = ftell(file->handle.std); } + if ((signed) result == -1) + fatal("%s: Could not determine position of file '%s'!\n", + file->module, file->name); + return result; } /* @@ -532,7 +569,7 @@ gbfeof(gbfile *file) res = gzeof(file->handle.gz); if (!res) { - signed char test; + unsigned char test; int len = gzread(file->handle.gz, &test, 1); if (len == 1) { /* No EOF, put the single byte back into stream */ @@ -597,7 +634,8 @@ gbfgetint32(gbfile *file) { char buf[4]; - gbfread(&buf, 1, sizeof(buf), file); + is_fatal((gbfread(&buf, 1, sizeof(buf), file) != sizeof(buf)), + "%s: Unexpected end of file (%s)!\n", file->module, file->name); if (file->big_endian) return be_read32(buf); @@ -614,7 +652,8 @@ gbfgetint16(gbfile *file) { char buf[2]; - gbfread(&buf, 1, sizeof(buf), file); + is_fatal((gbfread(&buf, 1, sizeof(buf), file) != sizeof(buf)), + "%s: Unexpected end of file (%s)!\n", file->module, file->name); if (file->big_endian) return be_read16(buf); @@ -631,7 +670,8 @@ gbfgetdbl(gbfile *file) { char buf[8]; - gbfread(&buf, 1, sizeof(buf), file); + is_fatal((gbfread(&buf, 1, sizeof(buf), file) != sizeof(buf)), + "%s: Unexpected end of file (%s)!\n", file->module, file->name); return endian_read_double(buf, ! file->big_endian); } @@ -645,7 +685,8 @@ gbfgetflt(gbfile *file) { char buf[4]; - gbfread(&buf, 1, sizeof(buf), file); + is_fatal((gbfread(&buf, 1, sizeof(buf), file) != sizeof(buf)), + "%s: Unexpected end of file (%s)!\n", file->module, file->name); return endian_read_float(buf, ! file->big_endian); } diff --git a/gbfile.h b/gbfile.h index 7b1d28a7b..545ebfc68 100644 --- a/gbfile.h +++ b/gbfile.h @@ -60,6 +60,7 @@ gbsize_t gbfread(void *buf, const gbsize_t size, const gbsize_t members, gbfile int gbfgetc(gbfile *file); char *gbfgets(char *buf, int len, gbfile *file); +int gbvfprintf(gbfile *file, const char *format, va_list ap); int gbfprintf(gbfile *file, const char *format, ...); int gbfputc(int c, gbfile *file); int gbfputs(const char *s, gbfile *file); diff --git a/gbser_posix.c b/gbser_posix.c index c2c6cab3c..4667ffce3 100644 --- a/gbser_posix.c +++ b/gbser_posix.c @@ -305,7 +305,16 @@ int gbser__fill_buffer(void *handle, unsigned want, unsigned *ms) { vmin = want - h->inbuf_used; vtime = (unsigned) time_left / 100; } - if ((rc = set_rx_timeout(h, vmin, vtime), rc < 0) || + // The commented out call to set_rx_timeout here is totally + // legal by POSIX standards but does result in a flurry of + // of tcsetattrs that slightly tweak VMIN/VTIME while there + // is incoming data. This has been shown to trigger driver + // bugs in the Prolific drivers for Mac and in certain Linux + // kernels, thought the latter has since been fixed. + // So althogh removing this means that the timeout behaviour + // is actually different on POSIX and WIN32, it triggers + // fewer buts this way. 2/12/2008 RJL + if (/* (rc = set_rx_timeout(h, vmin, vtime), rc < 0) || */ (rc = read(h->fd, h->inbuf + h->inbuf_used, want - h->inbuf_used), rc < 0)) { return gbser_ERROR; diff --git a/gbversion.h b/gbversion.h index bcd591b2e..070161cad 100644 --- a/gbversion.h +++ b/gbversion.h @@ -4,5 +4,5 @@ * * Isn't simplification via automation grand? */ -#define VERSION "1.3.4" - +#define VERSION "1.3.5" +#define WEB_DOC_DIR "http://www.gpsbabel.org/htmldoc-1.3.5" diff --git a/gbversion.h.in b/gbversion.h.in index db491f99e..e15e4bb11 100644 --- a/gbversion.h.in +++ b/gbversion.h.in @@ -5,4 +5,4 @@ * Isn't simplification via automation grand? */ #define VERSION "@GBMAJOR@.@GBMINOR@.@GBMICRO@@PACKAGE_RELEASE@" - +#define WEB_DOC_DIR "http://www.gpsbabel.org/htmldoc-@DOCVERSION@" diff --git a/gdb.c b/gdb.c index e6fc0190c..7893dceec 100644 --- a/gdb.c +++ b/gdb.c @@ -1,7 +1,7 @@ /* Garmin GPS Database Reader/Writer - Copyright (C) 2005,2006,2007 Olaf Klein, o.b.klein@gpsbabel.org + Copyright (C) 2005-2008 Olaf Klein, o.b.klein@gpsbabel.org Mainly based on mapsource.c, Copyright (C) 2005 Robert Lipe, robertlipe@usa.net @@ -57,6 +57,8 @@ 2007/05/03: Add code for tricky V3 descriptions 2007/06/18: Tweak some forgotten "flagged" fields 2007/07/07: Better support for new fields since V3 (postal code/street address/instruction) + 2008/01/09: Fix handling of option category (cat) + 2008/04/27: Add zero to checklist of "unknown bytes" */ #include @@ -106,8 +108,8 @@ /*******************************************************************************/ -/* static char gdb_release[] = "$Revision: 1.58 $"; */ -static char gdb_release_date[] = "$Date: 2007/07/14 21:06:14 $"; +/* static char gdb_release[] = "$Revision: 1.65 $"; */ +static char gdb_release_date[] = "$Date: 2008/05/04 23:09:08 $"; static gbfile *fin, *fout; static int gdb_ver, gdb_category, gdb_via, gdb_roadbook; @@ -119,6 +121,7 @@ static char *gdb_opt_category; static char *gdb_opt_ver; static char *gdb_opt_via; static char *gdb_opt_roadbook; +static char *gdb_opt_bitcategory; static int waypt_flag; static int route_flag; @@ -441,6 +444,7 @@ read_waypoint(gt_waypt_classes_e *waypt_class_out) waypoint *res; garmin_fs_t *gmsd; char *str; + char *bufp = buf; #ifdef GMSD_EXPERIMENTAL char subclass[22]; #endif @@ -462,7 +466,7 @@ read_waypoint(gt_waypt_classes_e *waypt_class_out) if (wpt_class != 0) waypth_ct++; FREAD_STR(buf); /* Country code */ - GMSD_SETSTR(cc, buf); + GMSD_SETSTR(cc, bufp); #ifdef GMSD_EXPERIMENTAL FREAD(subclass, sizeof(subclass)); @@ -531,11 +535,11 @@ read_waypoint(gt_waypt_classes_e *waypt_class_out) icon = FREAD_i32; GMSD_SET(icon, icon); /* icon */ FREAD_STR(buf); /* city */ - GMSD_SETSTR(city, buf); + GMSD_SETSTR(city, bufp); FREAD_STR(buf); /* state */ - GMSD_SETSTR(state, buf); + GMSD_SETSTR(state, bufp); FREAD_STR(buf); /* facility */ - GMSD_SETSTR(facility, buf); + GMSD_SETSTR(facility, bufp); FREAD(buf, 1); @@ -580,7 +584,7 @@ read_waypoint(gt_waypt_classes_e *waypt_class_out) waypt_flag = 0; FREAD_STR(buf); /* street address */ - GMSD_SETSTR(addr, buf); + GMSD_SETSTR(addr, bufp); FREAD(buf, 5); /* instruction depended */ res->description = FREAD_CSTR; /* instruction */ @@ -636,13 +640,13 @@ read_waypoint(gt_waypt_classes_e *waypt_class_out) if (gdb_ver >= GDB_VER_3) { if (FREAD_i32 == 1) { FREAD_STR(buf); /* phone number */ - GMSD_SETSTR(phone_nr, buf); + GMSD_SETSTR(phone_nr, bufp); FREAD_STR(buf); /* ?? fax / mobile ?? */ } FREAD_STR(buf); /* country */ - GMSD_SETSTR(country, buf); + GMSD_SETSTR(country, bufp); FREAD_STR(buf); /* postal code */ - GMSD_SETSTR(postal_code, buf); + GMSD_SETSTR(postal_code, bufp); } res->icon_descr = gt_find_desc_from_icon_number(icon, GDB, &dynamic); @@ -730,7 +734,8 @@ read_route(void) } FREAD(buf, 18); /* unknown 18 bytes; but first should be 0x01 or 0x03 */ - if ((buf[0] != 0x01) && (buf[0] != 0x03)) { + /* seen also 0 with VER3 */ + if ((buf[0] != 0x00) && (buf[0] != 0x01) && (buf[0] != 0x03)) { int i; warnings++; @@ -1199,7 +1204,10 @@ write_waypoint( FWRITE_LATLON(wpt->latitude); /* latitude */ FWRITE_LATLON(wpt->longitude); /* longitude */ FWRITE_DBL(wpt->altitude, unknown_alt); /* altitude */ - FWRITE_CSTR(wpt->notes); + if (wpt->notes) + FWRITE_CSTR(wpt->notes); + else + FWRITE_CSTR(wpt->description); FWRITE_DBL(WAYPT_GET(wpt, proximity, unknown_alt), unknown_alt); /* proximity */ FWRITE_i32(display); /* display */ FWRITE_i32(0); /* color (colour) */ @@ -1625,6 +1633,16 @@ init_writer(const char *fname) gdb_category = (gdb_opt_category) ? atoi(gdb_opt_category) : 0; gdb_ver = (gdb_opt_ver && *gdb_opt_ver) ? atoi(gdb_opt_ver) : 0; + if (gdb_category) { + is_fatal((gdb_category < 1) || (gdb_category > 16), + MYNAME ": cat must be between 1 and 16!"); + gdb_category = 1 << (gdb_category - 1); + } + + if (gdb_opt_bitcategory) { + gdb_category = strtol(gdb_opt_bitcategory, NULL, 0); + } + if (gdb_ver >= GDB_VER_UTF8) cet_convert_init(CET_CHARSET_UTF8, 1); @@ -1676,12 +1694,15 @@ write_data(void) #define GDB_OPT_VER "ver" #define GDB_OPT_VIA "via" #define GDB_OPT_CATEGORY "cat" +#define GDB_OPT_BITCATEGORY "bitscategory" #define GDB_OPT_ROADBOOK "roadbook" static arglist_t gdb_args[] = { {GDB_OPT_CATEGORY, &gdb_opt_category, "Default category on output (1..16)", NULL, ARGTYPE_INT, "1", "16"}, + {GDB_OPT_BITCATEGORY, &gdb_opt_bitcategory, "Bitmap of categories", + NULL, ARGTYPE_INT, "1", "65535"}, {GDB_OPT_VER, &gdb_opt_ver, "Version of gdb file to generate (1..3)", "2", ARGTYPE_INT, "1", "3"}, @@ -1691,6 +1712,7 @@ static arglist_t gdb_args[] = { {GDB_OPT_ROADBOOK, &gdb_opt_roadbook, "Include major turn points (with description) from calculated route", NULL, ARGTYPE_BOOL, ARG_NOMINMAX}, + ARG_TERMINATOR }; diff --git a/google.c b/google.c index 0496d6422..889405696 100644 --- a/google.c +++ b/google.c @@ -353,9 +353,8 @@ google_read(void) panel = strstr( dict, "panel:\""); panelofs = 7; } - tmp = panel; - while ( tmp ) { + while ( tmp ) { if ( qc == '"' ) { char *tmp1 = strstr( tmp, "\"points\":\"" ); if ( !tmp1 ) { @@ -420,6 +419,9 @@ google_read(void) if ( panel ) { panel += panelofs; end = strstr( panel, "/table>
"); } } - if ( end ) { char *to = panel; char *from = panel; @@ -472,6 +473,12 @@ google_read(void) *to++='>'; from += 6; } + else if ( !strncmp( from, "\\x", 2)) { + unsigned int c; + sscanf(from+2, "%2x", &c); + *to++ = (char)c; + from += 4; + } else if ( !strncmp( from, "\\'", 2)) { *to++ = '\''; from += 2; @@ -497,6 +504,7 @@ google_read(void) #if 0 { FILE *foo = fopen( "foo.xml", "w" ); + fprintf(foo, "\n", xhtml_entities ); fwrite( panel, sizeof(char), strlen(panel), foo ); fclose( foo ); } diff --git a/gpsbabel.html b/gpsbabel.html index 2550b9dad..bbdf18a2a 100644 --- a/gpsbabel.html +++ b/gpsbabel.html @@ -1,37 +1,36 @@ - -GPSBabel Documentation

GPSBabel Documentation


Table of Contents

Introduction
The Problem: Too many incompatible GPS file formats
The Solution
1. Getting it and Building it
2. Usage
Invocation
Suboptions
Advanced Usage
Route and Track Modes
Working with predefined options
Realtime tracking
Batch mode (command files)
3. The Formats
? Character Separated Values (xcsv)
Alan Map500 tracklogs (.trl) (alantrl)
Alan Map500 waypoints and routes (.wpr) (alanwpr)
All database fields on one tab-separated line (tabsep)
Brauniger IQ Series Barograph Download (baroiq)
Cambridge/Winpilot glider software (cambridge)
CarteSurTable data file (cst)
Cetus for Palm/OS (cetus)
CoastalExplorer XML (coastexp)
Comma separated values (csv)
CompeGPS data files (.wpt/.trk/.rte) (compegps)
CoPilot Flight Planner for Palm/OS (copilot)
cotoGPS for Palm/OS (coto)
Custom "Everything" Style (custom)
Dell Axim Navigation System (.gpb) file format (axim_gpb)
DeLorme .an1 (drawing) file (an1)
DeLorme GPL (gpl)
DeLorme Street Atlas Plus (saplus)
DeLorme Street Atlas Route (saroute)
DeLorme XMap HH Native .WPT (xmap)
DeLorme XMap/SAHH 2006 Native .TXT (xmap2006)
DeLorme XMat HH Street Atlas USA .WPT (PPC) (xmapwpt)
EasyGPS binary format (easygps)
FAI/IGC Flight Recorder Data Format (igc)
Franson GPSGate Simulation (gpssim)
Fugawi (fugawi)
G7ToWin data files (.g7t) (g7towin)
Garmin 301 Custom position and heartrate (garmin301)
Garmin Logbook XML (glogbook)
Garmin MapSource - gdb (gdb)
Garmin MapSource - mps (mapsource)
Garmin MapSource - txt (tab delimited) (garmin_txt)
Garmin PCX5 (pcx)
Garmin POI database (garmin_poi)
Garmin Points of Interest (.gpi) (garmin_gpi)
Garmin serial/USB protocol (garmin)
Garmin Training Centerxml (gtrnctr)
Geocaching.com .loc (geo)
GeocachingDB for Palm/OS (gcdb)
Geogrid Viewer tracklogs (.log) (ggv_log)
GEOnet Names Server (GNS) (geonet)
GeoNiche .pdb (geoniche)
Google Earth (Keyhole) Markup Language (kml)
Google Maps XML (google)
GpilotS (gpilots)
GPS TrackMaker (gtm)
GPSBabel arc filter file (arc)
GpsDrive Format (gpsdrive)
GpsDrive Format for Tracks (gpsdrivetrack)
GPSman (gpsman)
GPSPilot Tracker for Palm/OS (gpspilot)
gpsutil (gpsutil)
GPX XML (gpx)
HikeTech (hiketech)
Holux (gm-100) .wpo Format (holux)
HSA Endeavour Navigator export File (hsandv)
HTML Output (html)
IGN Rando track files (ignrando)
Kartex 5 Track File (ktf2)
Kartex 5 Waypoint File (kwf2)
Kompass (DAV) Track (.tk) (kompass_tk)
Kompass (DAV) Waypoints (.wp) (kompass_wp)
KuDaTa PsiTrex text (psitrex)
Lowrance USR (lowranceusr)
Magellan Explorist Geocaching (maggeo)
Magellan Mapsend (mapsend)
Magellan NAV Companion for Palm/OS (magnav)
Magellan SD files (as for eXplorist) (magellanx)
Magellan SD files (as for Meridian) (magellan)
Magellan serial protocol (magellan)
Map&Guide 'TourExchangeFormat' XML (tef)
Map&Guide to Palm/OS exported files (.pdb) (mag_pdb)
Mapopolis.com Mapconverter CSV (mapconverter)
MapTech Exchange Format (mxf)
Microsoft AutoRoute 2002 (pin/route reader) (msroute)
Microsoft Streets and Trips (pin/route reader) (msroute)
Microsoft Streets and Trips 2002-2006 (s_and_t)
Motorrad Routenplaner (Map&Guide) .bcr files (bcr)
MS PocketStreets 2002 Pushpin (psp)
National Geographic Topo .tpg (waypoints) (tpg)
National Geographic Topo 2.x .tpo (tpo2)
National Geographic Topo 3.x/4.x .tpo (tpo3)
Navicache.com XML (navicache)
Navigon Mobile Navigator .rte files (nmn4)
Navitrak DNA marker format (dna)
NetStumbler Summary File (text) (netstumbler)
NIMA/GNIS Geographic Names File (nima)
NMEA 0183 sentences (nmea)
OziExplorer (ozi)
PalmDoc Output (palmdoc)
PathAway Database for Palm/OS (pathaway)
Quovadis (quovadis)
Raymarine Waypoint File (.rwf) (raymarine)
See You flight analysis data (cup)
Sportsim track files (part of zipped .ssz files) (sportsim)
Suunto Trek Manager (STM) .sdf files (stmsdf)
Suunto Trek Manager (STM) WaypointPlus files (stmwpp)
Tab delimited fields useful for OpenOffice, Ploticus etc. (openoffice)
Textual Output (text)
TomTom Itineraries (.itn) (tomtom_itn)
TomTom POI file (.asc) (tomtom_asc)
TomTom POI file (.ov2) (tomtom)
TopoMapPro Places File (tmpro)
TrackLogs digital mapping (.trl) (dmtlog)
U.S. Census Bureau Tiger Mapping Service (tiger)
Universal csv with field structure in first line (unicsv)
Vcard Output (for iPod) (vcard)
Vito Navigator II tracks (vitosmt)
Vito SmartMap tracks (.vtt) (vitovtt)
WiFiFoFum 2.0 for PocketPC XML (wfff)
Wintec WBT-100/200 Binary File Format (wbt-bin)
Wintec WBT-100/200 GPS Download (wbt)
Wintec WBT-201/G-Rays 2 Binary File Format (wbt-tk1)
Yahoo Geocode API data (yahoo)
4. Data Filters
Include Only Points Inside Polygon (polygon)
Include Only Points Within Distance of Arc (arc)
Include Only Points Within Radius (radius)
Interpolate between trackpoints (interpolate)
Manipulate track lists (track)
Rearrange waypoints by resorting (sort)
Remove all waypoints, tracks, or routes (nuketypes)
Remove Duplicates (duplicate)
Remove Points Within Distance (position)
Remove unreliable points with high hdop or vdop (discard)
Reverse stops within routes (reverse)
Save and restore waypoint lists (stack)
Simplify routes (simplify)
Transform waypoints into a route, tracks into routes, ... (transform)
A. Supported Datums
B. Garmin Icons
C. GPSBabel XCSV Style Files
Introduction
Style file overview
Internal Constants
Global Properties of the File
GPSBabel Behavior Directives
Defining the Layout of the File
Defining Fields Within the File
Examples
Miscellaneous Notes
Glossary

List of Examples

3.1. Using gdb option roadbook to create simple html roadbook
3.2. Command showing garmin_txt output with all options
3.3. Command showing garmin_gpi output example
3.4. Sample BCR command with all options
3.5. Example for splitoutput option to text format
3.6. Command showing conversion of a Wintec binary file to GPX
3.7. Command showing WBT-200 download and erase over Bluetooth on Mac OS X
3.8. Command showing conversion of a Wintec binary file to GPX
4.1. Using the polygon filter
4.2. Using the polygon and arc filters to find points in or nearly in a +GPSBabel Documentation

GPSBabel Documentation


Table of Contents

Introduction
The Problem: Too many incompatible GPS file formats
The Solution
1. Getting it and Building it
2. Usage
Invocation
Suboptions
Advanced Usage
Route and Track Modes
Working with predefined options
Realtime tracking
Batch mode (command files)
3. The Formats
? Character Separated Values (xcsv)
Alan Map500 tracklogs (.trl) (alantrl)
Alan Map500 waypoints and routes (.wpr) (alanwpr)
All database fields on one tab-separated line (tabsep)
Brauniger IQ Series Barograph Download (baroiq)
Cambridge/Winpilot glider software (cambridge)
CarteSurTable data file (cst)
Cetus for Palm/OS (cetus)
CoastalExplorer XML (coastexp)
Comma separated values (csv)
CompeGPS data files (.wpt/.trk/.rte) (compegps)
CoPilot Flight Planner for Palm/OS (copilot)
cotoGPS for Palm/OS (coto)
Custom "Everything" Style (custom)
Dell Axim Navigation System (.gpb) file format (axim_gpb)
DeLorme .an1 (drawing) file (an1)
DeLorme GPL (gpl)
DeLorme Street Atlas Plus (saplus)
DeLorme Street Atlas Route (saroute)
DeLorme XMap HH Native .WPT (xmap)
DeLorme XMap/SAHH 2006 Native .TXT (xmap2006)
DeLorme XMat HH Street Atlas USA .WPT (PPC) (xmapwpt)
Destinator Itineraries (.dat) (destinator_itn)
Destinator Points of Interest (.dat) (destinator_poi)
Destinator TrackLogs (.dat) (destinator_trl)
EasyGPS binary format (easygps)
Embedded Exif-GPS data (.jpg) (exif)
FAI/IGC Flight Recorder Data Format (igc)
Franson GPSGate Simulation (gpssim)
Fugawi (fugawi)
G7ToWin data files (.g7t) (g7towin)
Garmin 301 Custom position and heartrate (garmin301)
Garmin Logbook XML (glogbook)
Garmin MapSource - gdb (gdb)
Garmin MapSource - mps (mapsource)
Garmin MapSource - txt (tab delimited) (garmin_txt)
Garmin PCX5 (pcx)
Garmin POI database (garmin_poi)
Garmin Points of Interest (.gpi) (garmin_gpi)
Garmin serial/USB protocol (garmin)
Garmin Training Centerxml (gtrnctr)
Geocaching.com .loc (geo)
GeocachingDB for Palm/OS (gcdb)
Geogrid Viewer tracklogs (.log) (ggv_log)
GEOnet Names Server (GNS) (geonet)
GeoNiche .pdb (geoniche)
GlobalSat DG-100/BT-335 Download (dg-100)
Google Earth (Keyhole) Markup Language (kml)
Google Maps XML (google)
GpilotS (gpilots)
GPS TrackMaker (gtm)
GPSBabel arc filter file (arc)
GpsDrive Format (gpsdrive)
GpsDrive Format for Tracks (gpsdrivetrack)
GPSman (gpsman)
GPSPilot Tracker for Palm/OS (gpspilot)
gpsutil (gpsutil)
GPX XML (gpx)
HikeTech (hiketech)
Holux (gm-100) .wpo Format (holux)
HSA Endeavour Navigator export File (hsandv)
HTML Output (html)
IGN Rando track files (ignrando)
Kartex 5 Track File (ktf2)
Kartex 5 Waypoint File (kwf2)
Kompass (DAV) Track (.tk) (kompass_tk)
Kompass (DAV) Waypoints (.wp) (kompass_wp)
KuDaTa PsiTrex text (psitrex)
Lowrance USR (lowranceusr)
Magellan Explorist Geocaching (maggeo)
Magellan Mapsend (mapsend)
Magellan NAV Companion for Palm/OS (magnav)
Magellan SD files (as for eXplorist) (magellanx)
Magellan SD files (as for Meridian) (magellan)
Magellan serial protocol (magellan)
MagicMaps IK3D project file (.ikt) (ik3d)
Map&Guide 'TourExchangeFormat' XML (tef)
Map&Guide to Palm/OS exported files (.pdb) (mag_pdb)
Mapopolis.com Mapconverter CSV (mapconverter)
MapTech Exchange Format (mxf)
Microsoft AutoRoute 2002 (pin/route reader) (msroute)
Microsoft Streets and Trips (pin/route reader) (msroute)
Microsoft Streets and Trips 2002-2007 (s_and_t)
Motorrad Routenplaner (Map&Guide) .bcr files (bcr)
MS PocketStreets 2002 Pushpin (psp)
MTK Logger (iBlue 747,...) Binary File Format (mtk-bin)
MTK Logger (iBlue 747,Qstarz BT-1000,...) download (mtk)
National Geographic Topo .tpg (waypoints) (tpg)
National Geographic Topo 2.x .tpo (tpo2)
National Geographic Topo 3.x/4.x .tpo (tpo3)
Navicache.com XML (navicache)
Navigon Mobile Navigator .rte files (nmn4)
NaviGPS GT-11/BGT-11 Download (navilink)
Navitrak DNA marker format (dna)
NetStumbler Summary File (text) (netstumbler)
NIMA/GNIS Geographic Names File (nima)
NMEA 0183 sentences (nmea)
Nokia Landmark Exchange (lmx)
OpenStreetMap data files (osm)
OziExplorer (ozi)
PalmDoc Output (palmdoc)
PathAway Database for Palm/OS (pathaway)
Quovadis (quovadis)
Raymarine Waypoint File (.rwf) (raymarine)
See You flight analysis data (cup)
Sportsim track files (part of zipped .ssz files) (sportsim)
Suunto Trek Manager (STM) .sdf files (stmsdf)
Suunto Trek Manager (STM) WaypointPlus files (stmwpp)
Swiss Map # (.xol) format (xol)
Tab delimited fields useful for OpenOffice, Ploticus etc. (openoffice)
Textual Output (text)
TomTom Itineraries (.itn) (tomtom_itn)
TomTom POI file (.asc) (tomtom_asc)
TomTom POI file (.ov2) (tomtom)
TopoMapPro Places File (tmpro)
TrackLogs digital mapping (.trl) (dmtlog)
U.S. Census Bureau Tiger Mapping Service (tiger)
Universal csv with field structure in first line (unicsv)
Vcard Output (for iPod) (vcard)
VidaOne GPS for Pocket PC (.gpb) (vidaone)
Vito Navigator II tracks (vitosmt)
Vito SmartMap tracks (.vtt) (vitovtt)
WiFiFoFum 2.0 for PocketPC XML (wfff)
Wintec WBT-100/200 Binary File Format (wbt-bin)
Wintec WBT-100/200 GPS Download (wbt)
Wintec WBT-201/G-Rays 2 Binary File Format (wbt-tk1)
Yahoo Geocode API data (yahoo)
4. Data Filters
Include Only Points Inside Polygon (polygon)
Include Only Points Within Distance of Arc (arc)
Include Only Points Within Radius (radius)
Interpolate between trackpoints (interpolate)
Manipulate track lists (track)
Rearrange waypoints by resorting (sort)
Remove all waypoints, tracks, or routes (nuketypes)
Remove Duplicates (duplicate)
Remove Points Within Distance (position)
Remove unreliable points with high hdop or vdop (discard)
Reverse stops within routes (reverse)
Save and restore waypoint lists (stack)
Simplify routes (simplify)
Transform waypoints into a route, tracks into routes, ... (transform)
A. Supported Datums
B. Garmin Icons
C. GPSBabel XCSV Style Files
Introduction
Style file overview
Internal Constants
Global Properties of the File
GPSBabel Behavior Directives
Defining the Layout of the File
Defining Fields Within the File
Examples
Miscellaneous Notes
Glossary

List of Examples

2.1. Command showing Linux download from Magellan serial and writing to .loc file
2.2. Command showing Windows download from Magellan serial and writing to .loc file
2.3. Merging multiple files into one
2.4. Merging multiple files of differing types.
2.5. Writing the same data in multiple output formats.
2.6. Read realtime positioning from Garmin USB, write to Keyhole Markup
3.1. Example 'csv' file
3.2. Example for gdb bitcategory option to put all waypoints in categories 1 and 16.
3.3. Using gdb option roadbook to create simple html roadbook
3.4. Command showing garmin_txt output with all options
3.5. Command showing garmin_gpi output example
3.6. Read GPX file, create GPI to alert when you're 1/2 mile from a speed camera.
3.7. Example for garmin bitcategory option to put all waypoints in categories 1 and 16.
3.8. Command showing DG-100 download and erase on Linux
3.9. Sample BCR command with all options
3.10. Convert MTK binary trackpoints to GPX
3.11. Command showing MTK download track and waypoints and erase on Linux
3.12. Example for splitoutput option to text format
3.13. Command showing conversion of a Wintec binary file to GPX
3.14. Command showing WBT-200 download and erase over Bluetooth on Mac OS X
3.15. Command showing conversion of a Wintec binary file to GPX
4.1. Using the polygon filter
4.2. Using the polygon and arc filters to find points in or nearly in a polygon
4.3. Using the arc filter
4.4. Using the radius filter to find points close to a given point
4.5. Using the interpolate filter
4.6. Time-shifting a track with the track filter
4.7. Merging tracks with the track filter
4.8. Extracting a period of time with the track filter
4.9. Filtering data types with nuketypes
4.10. Using the duplicate filter to suppress points with the same name and location
4.11. Using the duplicate filter to implement an "ignore list."
4.12. Using the duplicate filter to correct the locations of "puzzle" -geocaches
4.13. Using the position filter to suppress close points
4.14. Using the discard filter
4.15. Converting a track to a sequence of waypoints
4.16. Converting a pile of waypoints to a GPX route
4.17. Converting a pile of waypoints to a GPX track
4.18. Convert a GPX track to GPX waypoints, tossing the original track

Introduction

The Problem: Too many incompatible GPS file formats

There are simply too many gratuitously different file formats +geocaches

4.13. Using the position filter to suppress close points
4.14. Using the discard filter for HDOP and VDOP.
4.15. Using the discard filter to require at least three satellites.
4.16. Converting a track to a sequence of waypoints
4.17. Converting a pile of waypoints to a GPX route
4.18. Converting a pile of waypoints to a GPX track
4.19. Convert a GPX track to GPX waypoints, tossing the original track

Introduction

The Problem: Too many incompatible GPS file formats

There are simply too many gratuitously different file formats to hold waypoint, track, and route information in various programs used by computers and GPS receivers. -GPX defines a +GPX defines a standard in XML to contain all the data, but there are too many -programs that don't understand it yet and too much data that are in an +programs that don't understand it yet and too much data in alternate formats.

-Perhaps you have an Explorist 600 and your friend has a StreetPilot 2720. +Perhaps you have an Explorist 600 and your friend has a StreetPilot 2720. You've collected a a list of your favorite locations as waypoints and you'd -like to be able to share them. Unfortunately, his copy of Garmin Mapsource -won't read data created by your copy of Magellan Directroute. What you need +like to be able to share them. Unfortunately, his copy of Garmin Mapsource +won't read data created by your copy of Magellan Mapsend DirectRoute. What you need is a program that converts data bewteen the two programs.

-But GPSBabel actually does much more... -

The Solution

The original author of GPSBabel, Robert Lipe, needed to convert waypoints between a couple of formats, so he -whipped up a converter and based it on an extensible foundation so -that it was easy to add new formats and made the program freely available. Many others have contributed to the program since then.

Most file formats added so far have taken under 200 +GPSBabel actually solves that problem for you and much more... +

The Solution

The original author of GPSBabel, Robert Lipe, needed to convert waypoints between a couple of formats, so he +whipped up a converter and designed it upon an extensible foundation so +that it was easy to add new formats and made the program freely available. Many others have contributed to the program since then.

Most file formats added so far have taken under 200 lines of reasonable ISO C so they can be stamped out pretty trivially. Formats that are ASCII text delimited in some fixed way can be added with no programming at all via our - style mechanism. + style mechanism.

Chapter 1. Getting it and Building it

GPSBabel is distributed "ready to run" on most common operating systems via the -download page. +download page.

As GPSBabel runs on a wide variety of operating systems, be sure to visit the -OS-Specific notes for +OS-Specific notes for additional information.

For operating systems where no binary is provided or if @@ -41,19 +40,19 @@ ISO C89 compilers. It's been tested on UnixWare, OpenServer, OS/X, Linux, Solaris, and a variety of processors and compilers.

In most cases, the code is as simple to build as running: -

./configure && make

Expat +

./configure && make

Expat is strongly recommended for source builds as it is required for reading all the XML formats such as GPX. Fedora users -may need to 'yum install expat-devel'. Ubutnu users may need to +may need to 'yum install expat-devel'. Ubuntu users may need to 'apt-get install expat libexpat-dev'. -

libusb +

libusb is recommended for OS/X and Linux if you want to use a USB Garmin. -Fedora users may need to 'yum install expat-devel'. Ubutnu users may +Fedora users may need to 'yum install expat-devel'. Ubuntu users may need to 'apt-get install libusb-dev'.

There are additional flags that can be passed to configure to customize your build of GPSBabel.

./configure --help

-lists all the supported options, but additionally we have:

+lists all the supported options, but of interest we have:

--disable-shapefile Excludes the shapefile support.

--disable-pdb Excludes the Palm database support and all formats that rely on it. @@ -64,7 +63,7 @@ lists all the supported options, but additionally we have:

--enable-efence Activate debugging mode for gpsbabel-debug.

- --with-doc=dir Specify that the doc should be created and installed in dir. + --with-doc=dir Specifies that the doc should be created and installed in dir.

--without-libusb Disables use of libusb, even it's it's available.

@@ -73,37 +72,44 @@ lists all the supported options, but additionally we have:

If you're using GPSBabel, you will need to know how to do at least two things: read data from a file, and write it to another file. There are four basic options you need to know to do those things: -

CommandMeaning
-i formatSet input format
-f filenameRead file
-o formatSet output format
-F filenameWrite output File

+

CommandMeaning
-i formatSet input format
-f filenameRead file
-o formatSet output format
-F filenameWrite output file

Important

+Case matters. Notably -f (lowercase) sets the input file. -F (uppercase) sets the output file. +

The format parameters in the above list refer to the names of formats or file types supported by GPSBabel.

gpsbabel -?

will always show you the supported file types. In this document, the -various supported formats are listed in Chapter 3, The Formats. The +various supported formats are listed in Chapter 3, The Formats. The name that you would use on the command line follows the format name in parentheses.

Options are always processed in order from left to right. In practical terms, this means that things you want to read should appear -in the command before things you want to write. +in the command before things you want to write. This sometimes surprises +new users as adding options to turn on debugging at the end, for example, +doesn't work as the debugging is turned on after all the interesting work is +done. The reason for this strict ordering becomes more apparent once you +learn about mixing formats and filters.

The filename parameters specify the name of a file to be read or written.

To use - this program, just tell it what you're reading, where to read + GPSBabel in its simplest form, just tell it what you're reading, where to read it from, what you're writing, and what to write it to. For example:

gpsbabel -i geo -f /tmp/geocaching.loc -o gpx -F /tmp/geocaching.gpx

tells it to read the file /tmp/geocaching.loc in geocaching.com - format and create a new file /tmp/geocaching.gpx in GPX format. It's important to note that the names have nothign to do with the formats actually used.

This command will read from a Magellan unit attached + format and create a new file /tmp/geocaching.gpx in GPX format. It's important to note that the names have nothing to do with the formats actually used.

This command will read from a Magellan unit attached to the first serial port on a Linux system (device names will - vary on other OSes) and write them as a geocaching loc file.

gpsbabel -i magellan -f /dev/ttyS0 -o geo -F mag.loc

This second command does the same on Microsoft Windows.

gpsbabel -i magellan -f com1 -o geo -F mag.loc

Optionally, you may specify -s in any command line. This + vary on other OSes; typically COMx: on WIndows) and write them as a geocaching loc file.

Example 2.1. Command showing Linux download from Magellan serial and writing to .loc file

gpsbabel -i magellan -f /dev/ttyS0 -o geo -F mag.loc


This second command does the same on Microsoft Windows.

Example 2.2. Command showing Windows download from Magellan serial and writing to .loc file

gpsbabel -i magellan -f com1 -o geo -F mag.loc


Optionally, you may specify -s in any command line. This causes the program to ignore any "short" names that may be present in the source data format and synthesize one from the long name. This is particularly useful if you're writing to a target format that isn't the lowest common denominator but the source data was written for the lowest common - denominator. I use this for writing data from geocaching.com - to my Magellan so my waypoints have "real" names instead of - the 'GC1234' ones that are optimized for NMEA-only receivers. - A geocacher with a Magellan receiver may thus find commands - like this useful.

gpsbabel -s -i geo -f geocaching.loc -o magellan -F /dev/ttyS0

gpsbabel -s -i geo -f geocaching.loc -o magellan -F com1

Suboptions

+ denominator. This is useful for writing data from geocaching.com + to a GPS so my waypoints have "real" names instead of + the 'GC1234' ones that are optimized for receivers of the lowest + common denominator. + A geocacher using Linux with a Magellan receiver may thus find commands + like this useful.

gpsbabel -s -i geo -f geocaching.loc -o magellan -F /dev/ttyS0

His counterpart on Windows will find this equivalent

gpsbabel -s -i geo -f geocaching.loc -o magellan -F com1

Suboptions

Many of the available format options in GPSBabel can themselves take options. While we try to make all the formats do the most sensible thing possible without any extra options; this allows @@ -111,7 +117,7 @@ name of a file to be read or written.

Suboptions are comma separated and immediately follow the option itself. The available suboptions are listed on the individual - format pages. We'll make an example from the section called “Google Earth (Keyhole) Markup Language (kml)”: + format pages. We'll make an example from the section called “Google Earth (Keyhole) Markup Language (kml)”:

gpsbabel -i gpx -f file.gpx -o kml,deficon="file://myicon.png",lines=0 -F one.kml -o kml -F two.kml

This command will read the GPX file file.gpx and create two KML files. one.kml will @@ -128,19 +134,18 @@ name of a file to be read or written. line and are translated internally into a pipeline that data flows through when executed. Normally one would:

read from one input
optionally apply filters
write into one output

but GPSBabel is flexible enough to allow more complicated operations such as reading from several files (potentially of -different types), applying a filter, reading more data, then write the +different types), applying a filter, reading more data, then writing the merged data to multiple destinations.

The input file type remains unchanged until a new -i argument is seen. Files are read in the order they appear. So you could merge - three input files into one output file with:

gpsbabel -i geo -f 1.loc -f 2.loc -f 3.loc -o geo -F big.loc

You can merge files of different types:

gpsbabel -i geo -f 1.loc -i gpx -f 2.gpx -i pcx 3.pcx --o gpsutil -F big.gps

You can write the same data in different output formats:

gpsbabel -i geo -f 1.loc -o gpx -F 1.gpx -o pcx -F 1.wpt

If you want to change the character set of input or/and + three input files into one output file with:

Example 2.3. Merging multiple files into one

gpsbabel -i geo -f 1.loc -f 2.loc -f 3.loc -o geo -F big.loc


You can merge files of different types:

Example 2.4. Merging multiple files of differing types.

gpsbabel -i geo -f 1.loc -i gpx -f 2.gpx -i pcx 3.pcx -o gpsutil -F big.gps


Example 2.5. Writing the same data in multiple output formats.

You can write the same data in different output formats:

gpsbabel -i geo -f 1.loc -o gpx -F 1.gpx -o pcx -F 1.wpt


If you want to change the character set of input or/and output side you can do this with the option -c <character set>. You can get a complete list of supported character sets with "gpsbabel -l". To change the character set on both sides you should do this:

gpsbabel -i xcsv,style=foo.style -c latin1 -f foo -o xcsv,style=bar.style -c ms-ansi -F bar

Note, that some formats have a fixed character set and ignore this option.

Route and Track Modes

Most formats supported by GPSBabel will make a reasonable attempt to work transparently with waypoints, tracks, and routes. Some - formats, like garmin and magellan require the -t flag to work with tracks and + formats, like garmin and magellan require the -t flag to work with tracks and -r to work with routes. -w is for waypoints, and is the default. So if you wanted to read all @@ -182,9 +187,9 @@ merged data to multiple destinations. with '#' or ';' will be treated as comments and ignored.

There are three optional sections. -

  • "Common format settings"

    Any option from any of the formats listed here will be used by +

    • Common format settings.

      Any option from any of the formats listed here will be used by GPSBabel unless explictly provided on the command line. -

    • "Common filter settings"

      As above, but for filters.

    • Garmin categories

      This allows you to give readable names to the numeric categories +

    • Common filter settings.

      As above, but for filters.

    • Garmin categories

      This allows you to give readable names to the numeric categories used internally in some Garmin devices and the Mapsource formats such as GDB and MPS. This is information is also used by our GPX and garmin_txt formats as well.

    @@ -205,7 +210,7 @@ merged data to multiple destinations. inputs. KML, NMEA, and the variou XCSV formats are supported on output. Additional formats may be added by interested parties later. -

    gpsbabel -T -i garmin -f usb: -o kml -F xxx.kml

    +

    Example 2.6. Read realtime positioning from Garmin USB, write to Keyhole Markup

    gpsbabel -T -i garmin -f usb: -o kml -F xxx.kml


    Will read the USB-connected Garmin and rewrite 'xxx.kml' atomically, suitable for a self-refreshing network link in Google Earth.

Batch mode (command files)

@@ -220,7 +225,7 @@ merged data to multiple destinations. by placing the input and filtering directives in a file called 'all_my_files'.

gpsbabel -b all_my_files -o gdb -F all_my_tracks.gdb

'all_my_files' could look like this: -

-i gpx
-f saxony_in_summer_2004.gpx -f austria_2005.gpx
-i gdb
-f croatia_2006.gdb
-x nuketypes,waypoints,routes
-x track,pack,split,title="LOG # %Y%m%d"

Chapter 3. The Formats

Table of Contents

? Character Separated Values (xcsv)
Alan Map500 tracklogs (.trl) (alantrl)
Alan Map500 waypoints and routes (.wpr) (alanwpr)
All database fields on one tab-separated line (tabsep)
Brauniger IQ Series Barograph Download (baroiq)
Cambridge/Winpilot glider software (cambridge)
CarteSurTable data file (cst)
Cetus for Palm/OS (cetus)
CoastalExplorer XML (coastexp)
Comma separated values (csv)
CompeGPS data files (.wpt/.trk/.rte) (compegps)
CoPilot Flight Planner for Palm/OS (copilot)
cotoGPS for Palm/OS (coto)
Custom "Everything" Style (custom)
Dell Axim Navigation System (.gpb) file format (axim_gpb)
DeLorme .an1 (drawing) file (an1)
DeLorme GPL (gpl)
DeLorme Street Atlas Plus (saplus)
DeLorme Street Atlas Route (saroute)
DeLorme XMap HH Native .WPT (xmap)
DeLorme XMap/SAHH 2006 Native .TXT (xmap2006)
DeLorme XMat HH Street Atlas USA .WPT (PPC) (xmapwpt)
EasyGPS binary format (easygps)
FAI/IGC Flight Recorder Data Format (igc)
Franson GPSGate Simulation (gpssim)
Fugawi (fugawi)
G7ToWin data files (.g7t) (g7towin)
Garmin 301 Custom position and heartrate (garmin301)
Garmin Logbook XML (glogbook)
Garmin MapSource - gdb (gdb)
Garmin MapSource - mps (mapsource)
Garmin MapSource - txt (tab delimited) (garmin_txt)
Garmin PCX5 (pcx)
Garmin POI database (garmin_poi)
Garmin Points of Interest (.gpi) (garmin_gpi)
Garmin serial/USB protocol (garmin)
Garmin Training Centerxml (gtrnctr)
Geocaching.com .loc (geo)
GeocachingDB for Palm/OS (gcdb)
Geogrid Viewer tracklogs (.log) (ggv_log)
GEOnet Names Server (GNS) (geonet)
GeoNiche .pdb (geoniche)
Google Earth (Keyhole) Markup Language (kml)
Google Maps XML (google)
GpilotS (gpilots)
GPS TrackMaker (gtm)
GPSBabel arc filter file (arc)
GpsDrive Format (gpsdrive)
GpsDrive Format for Tracks (gpsdrivetrack)
GPSman (gpsman)
GPSPilot Tracker for Palm/OS (gpspilot)
gpsutil (gpsutil)
GPX XML (gpx)
HikeTech (hiketech)
Holux (gm-100) .wpo Format (holux)
HSA Endeavour Navigator export File (hsandv)
HTML Output (html)
IGN Rando track files (ignrando)
Kartex 5 Track File (ktf2)
Kartex 5 Waypoint File (kwf2)
Kompass (DAV) Track (.tk) (kompass_tk)
Kompass (DAV) Waypoints (.wp) (kompass_wp)
KuDaTa PsiTrex text (psitrex)
Lowrance USR (lowranceusr)
Magellan Explorist Geocaching (maggeo)
Magellan Mapsend (mapsend)
Magellan NAV Companion for Palm/OS (magnav)
Magellan SD files (as for eXplorist) (magellanx)
Magellan SD files (as for Meridian) (magellan)
Magellan serial protocol (magellan)
Map&Guide 'TourExchangeFormat' XML (tef)
Map&Guide to Palm/OS exported files (.pdb) (mag_pdb)
Mapopolis.com Mapconverter CSV (mapconverter)
MapTech Exchange Format (mxf)
Microsoft AutoRoute 2002 (pin/route reader) (msroute)
Microsoft Streets and Trips (pin/route reader) (msroute)
Microsoft Streets and Trips 2002-2006 (s_and_t)
Motorrad Routenplaner (Map&Guide) .bcr files (bcr)
MS PocketStreets 2002 Pushpin (psp)
National Geographic Topo .tpg (waypoints) (tpg)
National Geographic Topo 2.x .tpo (tpo2)
National Geographic Topo 3.x/4.x .tpo (tpo3)
Navicache.com XML (navicache)
Navigon Mobile Navigator .rte files (nmn4)
Navitrak DNA marker format (dna)
NetStumbler Summary File (text) (netstumbler)
NIMA/GNIS Geographic Names File (nima)
NMEA 0183 sentences (nmea)
OziExplorer (ozi)
PalmDoc Output (palmdoc)
PathAway Database for Palm/OS (pathaway)
Quovadis (quovadis)
Raymarine Waypoint File (.rwf) (raymarine)
See You flight analysis data (cup)
Sportsim track files (part of zipped .ssz files) (sportsim)
Suunto Trek Manager (STM) .sdf files (stmsdf)
Suunto Trek Manager (STM) WaypointPlus files (stmwpp)
Tab delimited fields useful for OpenOffice, Ploticus etc. (openoffice)
Textual Output (text)
TomTom Itineraries (.itn) (tomtom_itn)
TomTom POI file (.asc) (tomtom_asc)
TomTom POI file (.ov2) (tomtom)
TopoMapPro Places File (tmpro)
TrackLogs digital mapping (.trl) (dmtlog)
U.S. Census Bureau Tiger Mapping Service (tiger)
Universal csv with field structure in first line (unicsv)
Vcard Output (for iPod) (vcard)
Vito Navigator II tracks (vitosmt)
Vito SmartMap tracks (.vtt) (vitovtt)
WiFiFoFum 2.0 for PocketPC XML (wfff)
Wintec WBT-100/200 Binary File Format (wbt-bin)
Wintec WBT-100/200 GPS Download (wbt)
Wintec WBT-201/G-Rays 2 Binary File Format (wbt-tk1)
Yahoo Geocode API data (yahoo)

? Character Separated Values (xcsv)

+

-i gpx
-f saxony_in_summer_2004.gpx -f austria_2005.gpx
-i gdb
-f croatia_2006.gdb
-x nuketypes,waypoints,routes
-x track,pack,split,title="LOG # %Y%m%d"

Chapter 3. The Formats

Table of Contents

? Character Separated Values (xcsv)
Alan Map500 tracklogs (.trl) (alantrl)
Alan Map500 waypoints and routes (.wpr) (alanwpr)
All database fields on one tab-separated line (tabsep)
Brauniger IQ Series Barograph Download (baroiq)
Cambridge/Winpilot glider software (cambridge)
CarteSurTable data file (cst)
Cetus for Palm/OS (cetus)
CoastalExplorer XML (coastexp)
Comma separated values (csv)
CompeGPS data files (.wpt/.trk/.rte) (compegps)
CoPilot Flight Planner for Palm/OS (copilot)
cotoGPS for Palm/OS (coto)
Custom "Everything" Style (custom)
Dell Axim Navigation System (.gpb) file format (axim_gpb)
DeLorme .an1 (drawing) file (an1)
DeLorme GPL (gpl)
DeLorme Street Atlas Plus (saplus)
DeLorme Street Atlas Route (saroute)
DeLorme XMap HH Native .WPT (xmap)
DeLorme XMap/SAHH 2006 Native .TXT (xmap2006)
DeLorme XMat HH Street Atlas USA .WPT (PPC) (xmapwpt)
Destinator Itineraries (.dat) (destinator_itn)
Destinator Points of Interest (.dat) (destinator_poi)
Destinator TrackLogs (.dat) (destinator_trl)
EasyGPS binary format (easygps)
Embedded Exif-GPS data (.jpg) (exif)
FAI/IGC Flight Recorder Data Format (igc)
Franson GPSGate Simulation (gpssim)
Fugawi (fugawi)
G7ToWin data files (.g7t) (g7towin)
Garmin 301 Custom position and heartrate (garmin301)
Garmin Logbook XML (glogbook)
Garmin MapSource - gdb (gdb)
Garmin MapSource - mps (mapsource)
Garmin MapSource - txt (tab delimited) (garmin_txt)
Garmin PCX5 (pcx)
Garmin POI database (garmin_poi)
Garmin Points of Interest (.gpi) (garmin_gpi)
Garmin serial/USB protocol (garmin)
Garmin Training Centerxml (gtrnctr)
Geocaching.com .loc (geo)
GeocachingDB for Palm/OS (gcdb)
Geogrid Viewer tracklogs (.log) (ggv_log)
GEOnet Names Server (GNS) (geonet)
GeoNiche .pdb (geoniche)
GlobalSat DG-100/BT-335 Download (dg-100)
Google Earth (Keyhole) Markup Language (kml)
Google Maps XML (google)
GpilotS (gpilots)
GPS TrackMaker (gtm)
GPSBabel arc filter file (arc)
GpsDrive Format (gpsdrive)
GpsDrive Format for Tracks (gpsdrivetrack)
GPSman (gpsman)
GPSPilot Tracker for Palm/OS (gpspilot)
gpsutil (gpsutil)
GPX XML (gpx)
HikeTech (hiketech)
Holux (gm-100) .wpo Format (holux)
HSA Endeavour Navigator export File (hsandv)
HTML Output (html)
IGN Rando track files (ignrando)
Kartex 5 Track File (ktf2)
Kartex 5 Waypoint File (kwf2)
Kompass (DAV) Track (.tk) (kompass_tk)
Kompass (DAV) Waypoints (.wp) (kompass_wp)
KuDaTa PsiTrex text (psitrex)
Lowrance USR (lowranceusr)
Magellan Explorist Geocaching (maggeo)
Magellan Mapsend (mapsend)
Magellan NAV Companion for Palm/OS (magnav)
Magellan SD files (as for eXplorist) (magellanx)
Magellan SD files (as for Meridian) (magellan)
Magellan serial protocol (magellan)
MagicMaps IK3D project file (.ikt) (ik3d)
Map&Guide 'TourExchangeFormat' XML (tef)
Map&Guide to Palm/OS exported files (.pdb) (mag_pdb)
Mapopolis.com Mapconverter CSV (mapconverter)
MapTech Exchange Format (mxf)
Microsoft AutoRoute 2002 (pin/route reader) (msroute)
Microsoft Streets and Trips (pin/route reader) (msroute)
Microsoft Streets and Trips 2002-2007 (s_and_t)
Motorrad Routenplaner (Map&Guide) .bcr files (bcr)
MS PocketStreets 2002 Pushpin (psp)
MTK Logger (iBlue 747,...) Binary File Format (mtk-bin)
MTK Logger (iBlue 747,Qstarz BT-1000,...) download (mtk)
National Geographic Topo .tpg (waypoints) (tpg)
National Geographic Topo 2.x .tpo (tpo2)
National Geographic Topo 3.x/4.x .tpo (tpo3)
Navicache.com XML (navicache)
Navigon Mobile Navigator .rte files (nmn4)
NaviGPS GT-11/BGT-11 Download (navilink)
Navitrak DNA marker format (dna)
NetStumbler Summary File (text) (netstumbler)
NIMA/GNIS Geographic Names File (nima)
NMEA 0183 sentences (nmea)
Nokia Landmark Exchange (lmx)
OpenStreetMap data files (osm)
OziExplorer (ozi)
PalmDoc Output (palmdoc)
PathAway Database for Palm/OS (pathaway)
Quovadis (quovadis)
Raymarine Waypoint File (.rwf) (raymarine)
See You flight analysis data (cup)
Sportsim track files (part of zipped .ssz files) (sportsim)
Suunto Trek Manager (STM) .sdf files (stmsdf)
Suunto Trek Manager (STM) WaypointPlus files (stmwpp)
Swiss Map # (.xol) format (xol)
Tab delimited fields useful for OpenOffice, Ploticus etc. (openoffice)
Textual Output (text)
TomTom Itineraries (.itn) (tomtom_itn)
TomTom POI file (.asc) (tomtom_asc)
TomTom POI file (.ov2) (tomtom)
TopoMapPro Places File (tmpro)
TrackLogs digital mapping (.trl) (dmtlog)
U.S. Census Bureau Tiger Mapping Service (tiger)
Universal csv with field structure in first line (unicsv)
Vcard Output (for iPod) (vcard)
VidaOne GPS for Pocket PC (.gpb) (vidaone)
Vito Navigator II tracks (vitosmt)
Vito SmartMap tracks (.vtt) (vitovtt)
WiFiFoFum 2.0 for PocketPC XML (wfff)
Wintec WBT-100/200 Binary File Format (wbt-bin)
Wintec WBT-100/200 GPS Download (wbt)
Wintec WBT-201/G-Rays 2 Binary File Format (wbt-tk1)
Yahoo Geocode API data (yahoo)

? Character Separated Values (xcsv)

This format can...

snlen option

Max synthesized shortname length.

@@ -289,7 +294,7 @@ Valid values for this option are 0 (off) and 1 (on). GPS datum (def. WGS 84).

This option specifies the GPS datum to be used on read or write. Valid values for this -option are listed in Appendix A, Supported Datums. +option are listed in Appendix A, Supported Datums.

Alan Map500 tracklogs (.trl) (alantrl)

This format can...

  • @@ -313,7 +318,7 @@ Still, if you use a GM101, GPSBabel will probably be able to convert your waypoints, routes and tracklogs.

    For more information on the Alan Map500 visit -Alan Germany. There is very informative forum, too. The forum language is German but posts in English will be answered, too. +Alan Germany. There is very informative forum, too. The forum language is German but posts in English will be answered, too.

Alan Map500 waypoints and routes (.wpr) (alanwpr)

This format can...

  • @@ -339,21 +344,21 @@ Still, if you use a GM101, GPSBabel will probably be able to convert your waypoints, routes and tracklogs.

    For more information on the Alan Map500 visit -Alan Germany. There is very informative forum, too. Forum language is German but posts in English will be answered, +Alan Germany. There is very informative forum, too. Forum language is German but posts in English will be answered, too.

All database fields on one tab-separated line (tabsep)

This format can...

  • read and write waypoints

-This format is derived from the xcsv +This format is derived from the xcsv format, so it has all of the same options as that format.

-This format, like the custom format, is +This format, like the custom format, is mainly used for the purpose of testing GPSBabel. It is supposed to contain one field for each piece of information supported by the -xcsv format writer, but it may not be entirely -in sync with the documentation at Appendix C, GPSBabel XCSV Style Files. +xcsv format writer, but it may not be entirely +in sync with the documentation at Appendix C, GPSBabel XCSV Style Files.

For a list of fields, see the style/tabsep.style file in the GPSBabel source distribution. @@ -361,7 +366,7 @@ distribution. This format can...

  • read tracks -

Serial download protocol for the Brauniger IQ series of +

Serial download protocol for the Brauniger IQ series of barograph recording flight instruments. This format creates a track of altitude vs time which can be merged with a GPS track of the same flight to create a three dimensional IGC file.

Cambridge/Winpilot glider software (cambridge)

@@ -369,11 +374,11 @@ of the same flight to create a three dimensional IGC file.

  • read and write waypoints

-This format is derived from the xcsv +This format is derived from the xcsv format, so it has all of the same options as that format.

Support for -Cambridge -and Winpilot +Cambridge +and Winpilot flight analysis and planning software for glider pilots.

CarteSurTable data file (cst)

This format can...

  • @@ -382,8 +387,8 @@ and Winpilot read tracks

  • read routes -

With this format we can read CarteSurTable data files. - CarteSurTable is a shareware program widely used in France. The data +

With this format we can read CarteSurTable data files. + CarteSurTable is a shareware program widely used in France. The data inside have to be seen as a mixture of a waypoints list, one route and several tracks.

Cetus for Palm/OS (cetus)

@@ -392,7 +397,7 @@ several tracks. read and write waypoints

  • read tracks -

  • Cetus GPS is a program for +

    Cetus GPS is a program for Palm/OS. Working with Ron Parker and Kjeld Jensen, we can now read and write files for that program.

    dbname option

    Database name. @@ -416,28 +421,33 @@ looking at a list of icons in Cetus. read and write routes

    This is the format used by CoastalExplorer™. The format is XML with items uniquely identified by Windows-style UUIDs. -http://www.rosepointnav.com +http://www.rosepointnav.com

    Comma separated values (csv)

    This format can...

    • read and write waypoints

    -This format is derived from the xcsv +This format is derived from the xcsv format, so it has all of the same options as that format.

    There are a billion variants of Comma Separated Value -data. This is the one that makes Delorme S&A Deluxe 9™ happy. It's +data. This is the one specifically that makes Delorme S&A Deluxe 9™ happy. It's also a very simple program and useful for many other programs like spreadsheets.

    CSV is also the correct format for Lowrance MapCreate™, their commercial mapping program, or GDM6 (their free waypoint -manager) for iFinder which is available at lowrance.com +manager) for iFinder which is available at lowrance.com

    On write, this format writes simple "latitude, longitude" pairs, but -on read it will read anything supported by our human readable definition. +on read it will read anything supported by our human readable definition.

    For something-separated data that has headers identifying the various - fields, see our universal csv format. -

    CompeGPS data files (.wpt/.trk/.rte) (compegps)

    + fields, see our universal csv format. +

    Example 3.1. Example 'csv' file

    +35.97203, -87.13470, Mountain Bike Heaven by susy1313
    +36.09068, -86.67955, The Troll by a182pilot & Family
    +35.99627, -86.62012, Dive Bomber by JoGPS & family
    +36.03848, -86.64862, FOSTER by JoGPS & Family
    +

    CompeGPS data files (.wpt/.trk/.rte) (compegps)

    This format can...

    • read and write waypoints @@ -454,7 +464,7 @@ Since release 6.1 of CompeGPS™, GPX is also a supported import/export format for waypoints, routes and tracks.

      For more information please have a look at -http://www.compegps.com +http://www.compegps.com

      deficon option

      Default icon name.

      @@ -465,7 +475,7 @@ This option specifies the default icon name on output. Because this format supports only one route or track, this option may be used on output to select a single route or track from a collection of routes and tracks read from a more expressive format. If you have, say, a -gpx file that contains two routes, you may +gpx file that contains two routes, you may use this option to write them one at a time to individual files.

      gpsbabel -i gpx -f routes.gpx -o compegps,index=1 -F route1.txt -o compegps,index=2 -F route2.txt

      radius option

      Give points (waypoints/route points) a default radius (proximity). @@ -480,15 +490,15 @@ The default length is 16. This format can...

      • read and write waypoints -

      This code is mostly intended to convert CoPilot Flight +

    This code is mostly intended to convert CoPilot Flight Planner for Palm/OS" databases into other formats. You probably should not use this to write CoPilot databases, although the code is there, because GPSBabel doesn't convert magnetic declination values.

    This version now reads all CoPilot file versions up to 4, but only writes version 4 files. If you have a need for a version flag, please let me know.

    Questions, bug reports, etc, to ptomblin at xcski.com

    - http://xcski.com/~ptomblin/CoPilot/ -and http://navaid.com/CoPilot + http://xcski.com/~ptomblin/CoPilot/ +and http://navaid.com/CoPilot

    cotoGPS for Palm/OS (coto)

    This format can...

    • @@ -509,7 +519,7 @@ of the cotoGPS track format to the notes field.

      Contributed by Tobias Minich.

      -cotoGPS +cotoGPS

      zerocat option

      Name of the 'unassigned' category.

      @@ -520,7 +530,7 @@ database. The default is "Not Assigned".

      • read and write waypoints

      -This format is derived from the xcsv +This format is derived from the xcsv format, so it has all of the same options as that format.

      This format is not actually used by any real product. It is most useful @@ -528,14 +538,14 @@ for debugging purposes when developing a new format module for GPSBabel.

      To understand the contents of this file, look at the style/custom.style file in the GPSBabel source -distribution as well as Appendix C, GPSBabel XCSV Style Files. +distribution as well as Appendix C, GPSBabel XCSV Style Files.

      Dell Axim Navigation System (.gpb) file format (axim_gpb)

      This format can...

      • read tracks

      This format reads the binary (.gpb) track logs recorded on - Dell Axim Navigation Systems. + Dell Axim Navigation Systems.

      This is a read-only format for now as the format was reverse engineered and there are many unknown bytes. We can successfully @@ -549,7 +559,7 @@ distribution as well as read and write routes

    -This format supports the DeLorme ".an1" drawing file format. It can +This format supports the DeLorme ".an1" drawing file format. It can currently be used to either read or write drawing files. If you use this format to create drawing files with routes or waypoints from another source, by default it will create "Red Flag" symbols for waypoints, and @@ -588,7 +598,7 @@ Note that the ! is a shell metacharacter in bash and possibly other shells, so you may have to use single quotes or some other escape mechanism.

    There is a tutorial on -how +how to create an onramp for a limited access highway in Street Atlas USA using GPSBabel.

    nogc option

    @@ -654,13 +664,13 @@ specified in kilometers by adding a 'k'. The default radius is 1/10 mile. read and write tracks

    This is the 'gpl' format as used in Delorme mapping products. It is a track format and contains little more than the -tracklog of a GPS that was attached while driving. frontiernet.net +tracklog of a GPS that was attached while driving. frontiernet.net

    DeLorme Street Atlas Plus (saplus)

    This format can...

    • read and write waypoints

    -This format is derived from the xcsv +This format is derived from the xcsv format, so it has all of the same options as that format.

    This format is for Delorme Street Atlas USA 2004 Plus and later.

    For geocachers importing data from a tool like GSAK or @@ -718,10 +728,10 @@ travel speeds in the DeLorme product you used to create the route file.)

    • read and write waypoints

    -This format is derived from the xcsv +This format is derived from the xcsv format, so it has all of the same options as that format.

    Delorme TopoUSA/XMap Conduit is one of the bazillion -CSV variants +CSV variants variants mentioned above. It's just like Delorme Streets & Atlas with the addition of a completely pointless line at the beginning and end of the file. This is the format used to hot-sync to XMap from withing TopoUSA. Done with @@ -730,10 +740,10 @@ help of Dan Edwards.

    • read and write waypoints

    -This format is derived from the xcsv +This format is derived from the xcsv format, so it has all of the same options as that format.

    Delorme XMap2006 Conduit is just like -XMap +XMap , except there are no spaces between fields and the coordinate format is slightly different. The completely pointless header and footer lines @@ -743,15 +753,15 @@ format, so it has all of the same options as that format.

    • read and write waypoints

    -This format is derived from the xcsv +This format is derived from the xcsv format, so it has all of the same options as that format.

    Delorme XMapHandHeld Street Atlas USA is another of the -billion CSV variants. +billion CSV variants. This is the format used by XmapHH SA USA on (at least) PocketPC O/S.

    This XMap is not the same as the simpler -XMap format, which is used with Topo USA 4.0 +XMap format, which is used with Topo USA 4.0 and XMapHH for Palm.

    Delorme XMap Handheld .WPT for PocketPC is a bit of a kludge. This @@ -811,17 +821,94 @@ while (<INFILE>) { exit; -

    Contributed to GPSBabel by Alex Mottram.

    EasyGPS binary format (easygps)

    +

    Contributed to GPSBabel by Alex Mottram.

    Destinator Itineraries (.dat) (destinator_itn)

    + This format can... +

    • + read and write routes +

    + Support for Destinator™ itinerary files. +

    + These have (mostly) extension .dat and are binary files. The file structure is undocumented + and so this format was reverse engineered from some .dat files. + At this time we can read and write name, comment and the coordinates of the route points. +

    + Destinator™ by + Destinator Technologies + is a software for PNDs, Smartphones and PDAs. +

    + + gpsbabel -i destinator_itn -f from_A_to_B.dat -o gpx -F from_A_to_B.gpx + +

    Destinator Points of Interest (.dat) (destinator_poi)

    + This format can... +

    • + read and write waypoints +

    + Support for Destinator™ binary POI files (.dat). +

    + The basic information was found at mozoft.com. + GPSBabel can read and write all fields described at this document. Please note that 'house number' isn't + supported as a separate field. This field, if available in any source file, will be stored together with 'street' + into GSPBabel's internal 'address' field. +

    + Destinator™ by + Destinator Technologies + is a software for PNDs, Smartphones and PDAs. +

    + + gpsbabel -i destinator_poi -f interesting_places.dat -o gpx -F interesting_places.gpx + +

    Destinator TrackLogs (.dat) (destinator_trl)

    + This format can... +

    • + read and write tracks +

    + Support for Destinator™ binary tracklogs (.dat). +

    + The basic information was found at mozoft.com. + In addition to the standard GPS track data of coordinates and timestamp, this format also stores the + position fix and the number of satelites seen during recording. +

    + Destinator™ by + Destinator Technologies + is a software for PNDs, Smartphones and PDAs. +

    + + gpsbabel -i destinator_trl -f last_trip.dat -o gpx -F last_trip.gpx + +

    EasyGPS binary format (easygps)

    This format can...

    • read and write waypoints -

    This is the binary file format used by EasyGPS +

    This is the binary file format used by EasyGPS format is seemingly being phased out in favor of GPX in newer versions of EasyGPS, but this allows conversions to and from the old binary .loc format.

    Information about and sketchy code to implement this file format were provided by Eric Cloninger. -

    FAI/IGC Flight Recorder Data Format (igc)

    +

    Embedded Exif-GPS data (.jpg) (exif)

    + This format can... +

    • + read waypoints +

    + This format reads GPS information embedded in + EXIF , + the Exchangeable Image Format, data. EXIF is a standardized method + of encoding data in pictures such as JPEG, TIFF, and WAV and is frequently + used by mobile phones with cameras, cameras with built-in GPS. +

    + EXIF is frequently used for Geolocating photographs so their images can be + correlated with time and location. +

    filename option

    + Set waypoint name to source filename.. +

    + With this default option waypoint names are generated from source filename. +

    + + gpsbabel -i exif -f "C:\Pictures\IMG_1199.JPG",filename=Y -o gpx -F OUT.GPX + + The resulting waypoint in OUT.GPX has name IMG_1199. +

    FAI/IGC Flight Recorder Data Format (igc)

    This format can...

    This is a write-only format used to feed waypoints, tracks, and routes - into Franson Technolgies' - GpsGate simulator. + into Franson Technolgies' + GpsGate simulator.

    To use these files in GpsGate, select 'Simulator' and then "File->Open". @@ -951,17 +1038,17 @@ Valid values for this option are 0 (off) and 1 (on). The default is '0'.

    • read and write waypoints

    -This format is derived from the xcsv +This format is derived from the xcsv format, so it has all of the same options as that format. -

    This was a requested CSV format, and is not the proprietary -binary format used by Fugawi. Like any other CSV format, GPSBabel +

    This was a requested CSV format, and is not the proprietary +binary format used by Fugawi. Like any other CSV format, GPSBabel cannot read tracks in this format, but converting a track into it and then importing as track in Fugawi works.

    It is known to work with Fugawi V3.1.4.635. When importing/exporting waypoints, one has to specify the order of fields as follows (names of fields may depend on the language used by Fugawi):

    - Name
    - Comment
    - Description
    - Latidude
    - Longitude
    - Altitude (metres)
    - Date (yyyymmdd/yymmdd)
    - Time of day (hhmmss)

    When importing tracks, use "[ignore]" instead of "Name", "Comment" and "Description".

    - http://www.fugawi.com/ + http://www.fugawi.com/

    G7ToWin data files (.g7t) (g7towin)

    This format can...